目錄
AES加密
編碼
異或XOR
加解密步驟
AES加密

從中可以知道對稱加密和公鑰密碼只能保護機密性,防止竊聽,
如果要完整性防篡改,需要用單向散列函式、訊息認證碼、數字簽名技術,
這里有個關于對稱加密的一個問題:
如這個問題:對稱加密如AES,如果一串密文,有人稍微修了下,用密鑰去解會不會解出亂碼,還是解密失敗?拿java測,稍微測了幾次是解密失敗,但會不會有解出亂碼的情況?
問了一些大佬,最后總結出2個答案:
①一個鑰匙(密鑰)只能開一把鎖(加密資料),但這樣就有一個問題既然是這樣的模式,那么這個AES,不就具備了一部分了簽名的能力,就可以防篡改了,比如https,最后是用了AES加密,那么這個資料用AES加密,是否能防篡改,而上圖中對稱加密只用來保障機密性,所以這個地方就有點矛盾了,
②亂碼和失敗都是有可能,關鍵看AES是那種加密模式,是如果修改資料的,如果是使用流模式加密,能解密,但解出來的都是亂碼,塊加密模式只要不修改最后一塊就能解密,解出來是亂碼,塊加密模式修改最后一個塊,填充校驗失敗,不能解密,
這里我做了個實驗如下代碼:
AES.java
package cn.it1995.tool;
import javax.crypto.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class AES {
private SecretKey mKey;
public AES(){
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
//創建隨機密碼,并設定種子
SecureRandom secureRandom = new SecureRandom();
secureRandom.setSeed(System.currentTimeMillis());
//初始化密鑰物件
keyGenerator.init(128, secureRandom);
mKey = keyGenerator.generateKey();
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public byte[] encrypt(String content){
if(mKey == null){
return new byte[]{-1};
}
try {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, mKey);
return cipher.doFinal(content.getBytes());
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (NoSuchPaddingException e) {
e.printStackTrace();
}
catch (BadPaddingException e) {
e.printStackTrace();
}
catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
catch (InvalidKeyException e) {
e.printStackTrace();
}
return new byte[]{-1};
}
public byte[] decrypt(byte[] content){
if(mKey == null){
return new byte[]{-1};
}
try {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, mKey);
return cipher.doFinal(content);
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (NoSuchPaddingException e) {
e.printStackTrace();
}
catch (BadPaddingException e) {
e.printStackTrace();
}
catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
catch (InvalidKeyException e) {
e.printStackTrace();
}
return new byte[]{-1};
}
}
Main.java
package cn.it1995.tool;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
public class Main {
public static void main(String[] args) throws UnsupportedEncodingException {
String content = "helloWorldHelloWorld111111111111111111111111";
AES aes = new AES();
byte[] encrypted = aes.encrypt(new String(content));
byte[] decrypt = aes.decrypt(encrypted);
System.out.println("encrypted:" + new String(encrypted));
System.out.println("decrypt:" + new String(decrypt));
System.out.println("----------------------------------");
ByteBuffer bb = ByteBuffer.wrap(encrypted);
byte[] cipher = new byte[32];
bb.get(cipher, 0, 16);
for(int i = 5; i < 10; i++){
cipher[i] = 1;
}
for(int i = 0; i < 16; i++){
cipher[16 + i] = encrypted[encrypted.length - 16 + i];
}
System.out.println("洗掉(篡改)保留最后一塊:");
System.out.println(new String(aes.decrypt(cipher)));
}
}
運行截圖:

所以AES并不能防篡改,如果要防篡改需要用單向散列函式、訊息認證碼、數字簽名技術,
編碼
編碼:將現實世界中的東西映射為位元序列的操作,如midnight:
m->0110 1101
i->0110 1001
d->0110 0100
n->0110 1110
i->0110 1001
g->0110 0111
h->0110 1000
t->0111 0100
異或XOR
這個比較有意思以前的理解為相同為0,不同的為1,
這里看到了有人用棋盤翻轉的理解方式,
理解:0表示不翻轉,1表示翻轉,
0 XOR 0 = 0;沒有翻轉
1 XOR 0 = 1;翻轉了1次
0 XOR 1 = 1;翻轉了1次
1 XOR 1 = 0;翻轉了2次
加解密步驟
A XOR B = C
C XOR B = A
一串資料與密鑰運算,得到加密資料,加密資料在與密鑰運算獲取明文,
如下:
A:0100 1100
B:1010 1010
來計算一下:
A XOR B:
0100 1100
1010 1010
----------
1110 0110
結果 XOR B:
1110 0110
1010 1010
----------
0100 1100
這里有個結論:資料a異或資料b得到資料c,資料c再與資料資料b異或,可以得到資料a,
影像是這樣的:

下面使用Qt來實作這個加密,
編程實體
程式運行截圖如下:
先是一個蠟筆小新的彩色圖:

下面是《山坡羊·潼關懷古》

原理就是上面說的,通過這種方式實作圖片掩蓋,這里水印也可以這么搞,
工程如下:

原始碼如下:
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
uchar *m_secPtr;
uchar *m_xorPtr;
uchar *m_retPtr;
};
#endif // WIDGET_H
Widget.cpp
#include "Widget.h"
#include "ui_Widget.h"
#include <QImage>
#include <QDebug>
#include <QRandomGenerator>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QImage pix(":/tghg.png");
uchar *oriPtr = pix.bits();
int picSize = pix.sizeInBytes();
m_secPtr = new uchar[picSize];
m_xorPtr = new uchar[picSize];
m_retPtr = new uchar[picSize];
//生成密鑰圖片
for(int i = 0; i < picSize; i++){
m_secPtr[i] = QRandomGenerator::global()->bounded(256);
}
ui->originLabel->setPixmap(QPixmap::fromImage(pix));
ui->secLabel->setPixmap(QPixmap::fromImage(QImage(m_secPtr, pix.width(), pix.height(), pix.format())));
for(int i = 0; i < picSize; i++){
m_xorPtr[i] = oriPtr[i] ^ m_secPtr[i];
}
ui->xorLabel->setPixmap(QPixmap::fromImage(QImage(m_xorPtr, pix.width(), pix.height(), pix.format())));
//還原
for(int i = 0; i < picSize; i++){
m_retPtr[i] = m_xorPtr[i] ^ m_secPtr[i];
}
ui->retLabel->setPixmap(QPixmap::fromImage(QImage(m_retPtr, pix.width(), pix.height(), pix.format())));
}
Widget::~Widget()
{
delete ui;
delete this->m_retPtr;
delete this->m_secPtr;
delete this->m_xorPtr;
}
main.cpp
#include "Widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
原始碼打包下載地址:
Qt/XorPic at master · fengfanchen/Qt · GitHub
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/335450.html
標籤:其他
