引子
最近想研究STM32的 BootLoader 实现IAP升级,所以就有hex转bin且加密方面研究
这里主要是根据文章 **“STM32 IAP升级AES256加密 应用及源码” ** 来验证加密功能
最开始是看到 IAP+YMODEM+CRC16+AES256+PC端软件+hex合并 这里讲述的内容查询到方法
只是在这边加密步骤发现有些不一样,他们编译的 AES256.DLL 动态文件是 win32 ,而自己平台是 X64,简单调整一下即可!
AES算法详解
一、什么是AES?
AES(Advanced Encryption Standard)是一种对称加密算法,广泛应用于数据加密。它在2001年被美国国家标准与技术研究所(NIST)选为数据加密的标准,替代了之前的DES(Data Encryption Standard)。AES具有高效、安全和灵活的特点,适用于多种平台和环境。
二、AES的工作原理
AES是一种对称密钥加密算法,这意味着加密和解密使用同一个密钥。AES算法可以处理128位的块大小,支持128、192和256位的密钥长度。
加密过程
AES的加密过程包括多个步骤,主要分为以下几个阶段:
解密过程
解密过程与加密过程相似,但步骤的顺序和操作的内容会有所不同,具体步骤为:
三、AES的安全性
AES被认为是非常安全的加密标准,主要原因如下:
- 密钥长度:AES支持多种密钥长度,256位的密钥提供了极高的安全性。
- 抵抗力:AES设计抵抗多种攻击(如暴力破解、差分攻击、线性攻击等)。
- 标准化:作为NIST标准,AES得到了广泛的审查和验证。
四、AES的应用
AES被广泛应用于各种领域,包括但不限于:
- 数据保护:用于保护敏感数据,如金融信息、个人身份信息等。
- VPN和TLS:在虚拟私人网络和传输层安全(TLS)协议中用于数据加密。
- 文件加密:用于加密文件和存储设备,保护数据隐私。
- 电子商务:在在线支付和交易中保障数据安全。
语言实现(后边的文章使用了C++自己实现-这里基本使用库实现)
Go语言实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| package main import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/hex" "fmt" "io" )
func encrypt(plainText, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } plainText = pad(plainText) cipherText := make([]byte, len(plainText)) iv := make([]byte, aes.BlockSize) if _, err := io.ReadFull(rand.Reader, iv); err != nil { return nil, err } mode := cipher.NewCBCEncrypter(block, iv) mode.CryptBlocks(cipherText, plainText) return append(iv, cipherText...), nil }
func decrypt(cipherText, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } if len(cipherText) < aes.BlockSize { return nil, fmt.Errorf("ciphertext too short") } iv := cipherText[:aes.BlockSize] cipherText = cipherText[aes.BlockSize:] mode := cipher.NewCBCDecrypter(block, iv) mode.CryptBlocks(cipherText, cipherText) return unpad(cipherText), nil }
func pad(src []byte) []byte { padding := aes.BlockSize - len(src)%aes.BlockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(src, padtext...) }
func unpad(src []byte) []byte { length := len(src) unpadding := int(src[length-1]) return src[:(length - unpadding)] } func main() { key := []byte("thisisaverystrongkey1234") plainText := []byte("Hello, AES encryption!") cipherText, err := encrypt(plainText, key) if err != nil { fmt.Println("Encryption error:", err) return } fmt.Println("Cipher Text:", hex.EncodeToString(cipherText)) decryptedText, err := decrypt(cipherText, key) if err != nil { fmt.Println("Decryption error:", err) return } fmt.Println("Decrypted Text:", string(decryptedText)) }
|
Python实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad import os import binascii def encrypt(plain_text, key): cipher = AES.new(key, AES.MODE_CBC) iv = cipher.iv cipher_text = cipher.encrypt(pad(plain_text.encode(), AES.block_size)) return iv + cipher_text def decrypt(cipher_text, key): iv = cipher_text[:AES.block_size] cipher = AES.new(key, AES.MODE_CBC, iv) decrypted_text = unpad(cipher.decrypt(cipher_text[AES.block_size:]), AES.block_size) return decrypted_text.decode() if __name__ == "__main__": key = b'thisisaverystrong' plain_text = "Hello, AES encryption!" cipher_text = encrypt(plain_text, key) print("Cipher Text:", binascii.hexlify(cipher_text).decode()) decrypted_text = decrypt(cipher_text, key) print("Decrypted Text:", decrypted_text)
|
Java实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.util.Arrays; public class AESExample { private static final String ALGORITHM = "AES"; private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding"; public static byte[] encrypt(String plainText, byte[] key) throws Exception { SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM); Cipher cipher = Cipher.getInstance(TRANSFORMATION); byte[] iv = new byte[cipher.getBlockSize()]; System.arraycopy(key, 0, iv, 0, iv.length); cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); return cipher.doFinal(plainText.getBytes()); } public static String decrypt(byte[] cipherText, byte[] key) throws Exception { SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM); Cipher cipher = Cipher.getInstance(TRANSFORMATION); byte[] iv = new byte[cipher.getBlockSize()]; System.arraycopy(key, 0, iv, 0, iv.length); cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); return new String(cipher.doFinal(cipherText)); } public static void main(String[] args) { try { byte[] key = "thisisaverystrong".getBytes(); String plainText = "Hello, AES encryption!"; byte[] cipherText = encrypt(plainText, key); System.out.println("Cipher Text: " + Arrays.toString(cipherText)); String decryptedText = decrypt(cipherText, key); System.out.println("Decrypted Text: " + decryptedText); } catch (Exception e) { e.printStackTrace(); } } }
|
STM32 IAP升级AES256加密 应用及源码
我用的万利199元的板。
AES256加密算法,用的是shaoziyang的源码,由于不会用C++,上位机用了C#开发,搞了一个多星期,C#加密出来的,老是和shaoziyang的AVRUB加密出来的不一样,就干脆用C++做了DLL,用C#调用。
不多说了,直接上源码。
上位机效果图
STM32下位机IAP升级里面,我把固件上传部分删掉了,既然加密,就是为了防破_解,读出来就没必要了。
C++里的DLL加密文件包
点击此处下载 ourdev_678831FMG4A4.zip(文件大小:11K) (原文件名:DLLTest.zip)
C#写的调用DLL加密的HEX转Bin文件包
点击此处下载 ourdev_678832NPWI4U.zip(文件大小:45K) (原文件名:Hex2Bin.zip)
MDK下的万利199元开发板的IAP源码
点击此处下载 ourdev_678833DAXD3A.zip(文件大小:521K) (原文件名:Usart.zip)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 好像有问题把?
这是你写的程序: /*----------------------------------------------------------------------------------------------*/ BufferIn=buf; for (j = 0; j < packet_length; j += 16) { //解密数据包 aesDecrypt(BufferIn,bufferOut); BufferIn+=16; } /*----------------------------------------------------------------------------------------------*/ RamSource = (uint32_t)buf;
你最后的赋值又是没解密的内容啊?
是不是应该是RamSource = (uint32_t)bufferOut;
没搞过AES,你的函数也没什么仔细的说明,求解?
谢谢指导。
楼主| 发表于 2011-9-23 11:13:25 | 只看该作者 这个源码是从shaoziyang的AVR单片机通用BootLoader里提取出来的。
当时我也是你这种理解,参数1为输入,参数2为输出。但实际不是的,解密后的数据,实际还是在参数1的位置。
你仔细试试就知道了。
|
忘记说明了,加密Key设置如图。
Key字符串可用空格分隔,也可以不用。
注意: 最后使用的是
1
| 9D D2 00 24 84 60 2E DA 0C DD 52 7B 05 C1 6B 01 FF 17 CD 6F 8C 1E 3E 09 CF 1F 0C 78 87 EF 8A EC
|
编译出现的问题–调用DLL时 报“ 试图加载格式不正确的程序“
运行时报“试图加载格式不正确的程序。 (0x8007000B)”
主要是因为在 x64 架构上运行了 win32 的DLL导致
C#调用dll提示”试图加载格式不正确的程序”原因及解决方法
程序在32位操作系统上运行正常,在64位操作系统上运行读卡功能提示”试图加载格式不正确“。
出错原因:因为’任何 CPU’编译运行的程序在64位的机器上就会用运行为64位,而64位程序是不能加载32位dll的
解决方法:项目右键属性->项目设计器->生成->平台->把’默认设置(任何 CPU)’改为x86。
当将 DLL 库程序设置成 X86 之后编译会报错,主要还是因为使用了 C 语言编写
报错:
1
| 1>LINK : fatal error LNK1561: 必须定义入口点
|
解决64位dll“error LNK1561: 必须定义入口点”
在很多的时候需要生成一个64位的dll,但是明显在32位平台编译正确的代码,改成64位系统就不准确了,报“error LNK1561: 必须定义入口点”的错误。
- 五、然后到项目所在单位的win64目录下就可以找到生成的dll文件。
最终效果
根据文章得到了加密的 bin 文件了
C#中实现AES算法加密解读(直接使用库方式)
效果图
文件和加密文件之间的转换。
添加辅助类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
| public class AES_EnorDecrypt { private static byte[] _aesKeyByte = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; private static string _aesKeyStr = Encoding.UTF8.GetString(_aesKeyByte);
public static string GetIv(int n) { string s = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char[] arrChar = new char[s.Length]; for (int i = 0; i < s.Length; i++) { arrChar[i] = Convert.ToChar(s.Substring(i, 1)); } StringBuilder num = new StringBuilder(); Random rnd = new Random(DateTime.Now.Millisecond); for (int i = 0; i < n; i++) { num.Append(arrChar[rnd.Next(0, arrChar.Length)].ToString()); } _aesKeyByte = Encoding.UTF8.GetBytes(num.ToString()); return _aesKeyStr = Encoding.UTF8.GetString(_aesKeyByte); }
public static string AESEncrypt(string Data, string Key, string Vector) { byte[] plainBytes = Encoding.UTF8.GetBytes(Data); byte[] bKey = new byte[32]; Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length); byte[] bVector = new byte[16]; Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length); byte[] Cryptograph = null; Rijndael Aes = Rijndael.Create(); try { using (MemoryStream Memory = new MemoryStream()) { using (CryptoStream Encryptor = new CryptoStream(Memory, Aes.CreateEncryptor(bKey, bVector), CryptoStreamMode.Write)) { Encryptor.Write(plainBytes, 0, plainBytes.Length); Encryptor.FlushFinalBlock(); Cryptograph = Memory.ToArray(); } } } catch { Cryptograph = null; } return Convert.ToBase64String(Cryptograph); }
public static byte[] AESEncrypt(byte[] Data, string Key, string Vector) { byte[] bKey = new byte[32]; Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length); byte[] bVector = new byte[16]; Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length); byte[] Cryptograph = null; Rijndael Aes = Rijndael.Create(); try { using (MemoryStream Memory = new MemoryStream()) { using (CryptoStream Encryptor = new CryptoStream(Memory, Aes.CreateEncryptor(bKey, bVector), CryptoStreamMode.Write)) { Encryptor.Write(Data, 0, Data.Length); Encryptor.FlushFinalBlock(); Cryptograph = Memory.ToArray(); } } } catch { Cryptograph = null; } return Cryptograph; }
public static string AESDecrypt(string Data, string Key, string Vector) { byte[] encryptedBytes = Convert.FromBase64String(Data); byte[] bKey = new byte[32]; Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length); byte[] bVector = new byte[16]; Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length); byte[] original = null; Rijndael Aes = Rijndael.Create(); try { using (MemoryStream Memory = new MemoryStream(encryptedBytes)) { using (CryptoStream Decryptor = new CryptoStream(Memory, Aes.CreateDecryptor(bKey, bVector), CryptoStreamMode.Read)) { using (MemoryStream originalMemory = new MemoryStream()) { byte[] Buffer = new byte[1024]; int readBytes = 0; while ((readBytes = Decryptor.Read(Buffer, 0, Buffer.Length)) > 0) { originalMemory.Write(Buffer, 0, readBytes); } original = originalMemory.ToArray(); } } } } catch { original = null; } return Encoding.UTF8.GetString(original); }
public static byte[] AESDecrypt(byte[] Data, string Key, string Vector) { byte[] bKey = new byte[32]; Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length); byte[] bVector = new byte[16]; Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length); byte[] original = null; Rijndael Aes = Rijndael.Create(); try { using (MemoryStream Memory = new MemoryStream(Data)) { using (CryptoStream Decryptor = new CryptoStream(Memory, Aes.CreateDecryptor(bKey, bVector), CryptoStreamMode.Read)) { using (MemoryStream originalMemory = new MemoryStream()) { byte[] Buffer = new byte[1024]; int readBytes = 0; while ((readBytes = Decryptor.Read(Buffer, 0, Buffer.Length)) > 0) { originalMemory.Write(Buffer, 0, readBytes); } original = originalMemory.ToArray(); } } } } catch { original = null; } return original; } }
|
AES是块加密,块的长度是16字节,如果原文不到16的字节,就会进行填充至16个字节。
开始实现
界面布局
textbox1为文件位置,textbox2为密码。
backgroundWorker2也需要设置一样才行
设置好后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
| public partial class FormAes : Form { #region 属性 private static string _aesKeyVector = "q2T_=R/*33vc"; #endregion
public FormAes() { InitializeComponent(); }
private void textBox1_Click(object sender, EventArgs e) { OpenFileDialog dialog = new OpenFileDialog(); dialog.Multiselect = true; dialog.Title = "请选择文件夹"; dialog.Filter = "所有文件(*.*)|*.*"; if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) { textBox1.Text = dialog.FileName; } }
private void button1_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(textBox1.Text.Trim()) || string.IsNullOrWhiteSpace(textBox2.Text.Trim())) return; backgroundWorker1.RunWorkerAsync(); }
private void button2_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(textBox1.Text.Trim()) || string.IsNullOrWhiteSpace(textBox2.Text.Trim())) return; backgroundWorker2.RunWorkerAsync(); }
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { string KeyVector = _aesKeyVector; string path = Path.GetDirectoryName(textBox1.Text); string name = Path.GetFileName(textBox1.Text); name += ".En"; #region 加密 FileStream sr = new FileStream(textBox1.Text, FileMode.Open, FileAccess.Read); FileStream sw = new FileStream(path + "\\" + name, FileMode.Create, FileAccess.Write);
if (sr.Length > 50 * 1024 * 1024) { byte[] mybyte = new byte[52428800]; int numBytesRead = 52428800; long leftBytes = sr.Length; long readBytes = 0; byte[] encrpy = new byte[52428816]; while (true) { if (leftBytes > numBytesRead) { sr.Read(mybyte, 0, mybyte.Length); encrpy = AES_EnorDecrypt.AESEncrypt(mybyte, textBox2.Text, KeyVector); sw.Write(encrpy, 0, encrpy.Length); leftBytes -= numBytesRead; readBytes += numBytesRead; backgroundWorker1.ReportProgress((int)(readBytes * 100 / sr.Length)); } else { byte[] newByte = new byte[leftBytes]; sr.Read(newByte, 0, newByte.Length); byte[] newWriteByte; newWriteByte = AES_EnorDecrypt.AESEncrypt(newByte, textBox2.Text, KeyVector); sw.Write(newWriteByte, 0, newWriteByte.Length); readBytes += leftBytes; backgroundWorker1.ReportProgress((int)(readBytes * 100 / sr.Length)); break; } } } else { byte[] mybyte = new byte[sr.Length]; sr.Read(mybyte, 0, (int)sr.Length); mybyte = AES_EnorDecrypt.AESEncrypt(mybyte, textBox2.Text, KeyVector); sw.Write(mybyte, 0, mybyte.Length); backgroundWorker1.ReportProgress(100); }
sr.Close(); sw.Close();
#endregion } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar1.Value = e.ProgressPercentage; }
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { MessageBox.Show("加密成功!"); }
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e) { try { string KeyVector = _aesKeyVector; string path = Path.GetDirectoryName(textBox1.Text); string name = Path.GetFileName(textBox1.Text); if (name.EndsWith(".En")) { name = name.Remove(name.Length - 3, 3); }
#region 解密 FileStream sr = new FileStream(textBox1.Text, FileMode.Open, FileAccess.Read); FileStream sw = new FileStream(path + "\\" + name, FileMode.Create, FileAccess.Write);
if (sr.Length > 50 * 1024 * 1024) { byte[] mybyte = new byte[52428816]; byte[] decrpt = new byte[52428800]; int numBytesRead = 52428816; long leftBytes = sr.Length; long readBytes = 0; try { while (true) { if (leftBytes > numBytesRead) { sr.Read(mybyte, 0, mybyte.Length); decrpt = AES_EnorDecrypt.AESDecrypt(mybyte, textBox2.Text, KeyVector); sw.Write(decrpt, 0, decrpt.Length); leftBytes -= numBytesRead; readBytes += numBytesRead; backgroundWorker2.ReportProgress((int)(readBytes * 100 / sr.Length)); } else { byte[] newByte = new byte[leftBytes]; sr.Read(newByte, 0, newByte.Length); byte[] newWriteByte; newWriteByte = AES_EnorDecrypt.AESDecrypt(newByte, textBox2.Text, KeyVector); sw.Write(newWriteByte, 0, newWriteByte.Length); readBytes += leftBytes; backgroundWorker2.ReportProgress((int)(readBytes * 100 / sr.Length)); break; } } } catch { sr.Close(); sw.Close(); File.Delete(path + "\\" + name); e.Cancel = true; } sr.Close(); sw.Close(); } else { byte[] mybyte = new byte[(int)sr.Length]; sr.Read(mybyte, 0, (int)sr.Length); try { mybyte = AES_EnorDecrypt.AESDecrypt(mybyte, textBox2.Text, KeyVector); sw.Write(mybyte, 0, mybyte.Length); backgroundWorker2.ReportProgress(100); } catch { sr.Close(); sw.Close(); File.Delete(path + "\\" + name); e.Cancel = true; } sr.Close(); sw.Close(); } #endregion } catch { e.Cancel = true; } }
private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar1.Value = e.ProgressPercentage; }
private void backgroundWorker2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) { MessageBox.Show("解密失败\n密码错误或加密文件被篡改,无法解密"); } else { MessageBox.Show("解密成功!"); } } }
|
用C#实现AES加密和解密(库引用-没测试过)
AES 是一个新的可以用于保护电子数据的加密算法。明确地说,AES 是一个迭代的、对称密钥分组的密码,它可以使用128、192 和 256 位密钥,并且用 128 位(16字节)分组加密和解密数据。与公共密钥密码使用密钥对不同,对称密钥密码使用相同的密钥加密和解密数据。通过分组密码返回的加密数据 的位数与输入数据相同。迭代加密使用一个循环结构,在该循环中重复置换(permutations )和替换(substitutions)输入数据。
需要加入引用 using System.Security.Cryptography;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| public static string AESEncrypt(string text, string password, string iv) { RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
rijndaelCipher.KeySize = 128;
rijndaelCipher.BlockSize = 128;
byte[] pwdBytes = System.Text.Encoding.UTF8.GetBytes(password);
byte[] keyBytes = new byte[16];
int len = pwdBytes.Length;
if (len > keyBytes.Length) len = keyBytes.Length;
System.Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
byte[] ivBytes = System.Text.Encoding.UTF8.GetBytes(iv); rijndaelCipher.IV = ivBytes;
ICryptoTransform transform = rijndaelCipher.CreateEncryptor();
byte[] plainText = Encoding.UTF8.GetBytes(text);
byte[] cipherBytes = transform.TransformFinalBlock(plainText, 0, plainText.Length);
return Convert.ToBase64String(cipherBytes);
}
public static string GetIv(int n) { char[] arrChar = new char[]{ 'a','b','d','c','e','f','g','h','i','j','k','l','m','n','p','r','q','s','t','u','v','w','z','y','x', '0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','Q','P','R','T','S','V','U','W','X','Y','Z' };
StringBuilder num = new StringBuilder();
Random rnd = new Random(DateTime.Now.Millisecond); for (int i = 0; i < n; i++) { num.Append(arrChar[rnd.Next(0, arrChar.Length)].ToString());
}
return num.ToString(); }
public static string AESDecrypt(string text, string password, string iv) { RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
rijndaelCipher.KeySize = 128;
rijndaelCipher.BlockSize = 128;
byte[] encryptedData = Convert.FromBase64String(text);
byte[] pwdBytes = System.Text.Encoding.UTF8.GetBytes(password);
byte[] keyBytes = new byte[16];
int len = pwdBytes.Length;
if (len > keyBytes.Length) len = keyBytes.Length;
System.Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
byte[] ivBytes = System.Text.Encoding.UTF8.GetBytes(iv); rijndaelCipher.IV = ivBytes;
ICryptoTransform transform = rijndaelCipher.CreateDecryptor();
byte[] plainText = transform.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
return Encoding.UTF8.GetString(plainText);
}
|
AES加密算法详解(图文解释)
由于DES加密算法被破解了,3DES加密算法虽然没有被破解,但是3DES算法的加解密效率低,所有现在都使用AES算法。
AES加密算法是密码学中的高级加密标准,AES为分组加密法,把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文,在AES标准规范中,分组长度只能是128位,AES是按照字节进行加密的,也就是说每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位、192位或256位。这导致密钥长度不同,推荐加密的轮数也不同。
AES算法思想:
1)设计简单;
2)在多个平台上速度快,编码紧凑;
3)抵抗所有已知攻击;
4)没有采用Feistel结构,轮函数由3个不同的可逆均匀变换构成:非线性层、线性混合层和密钥加层。
明文P需要分组,称为状态,状态用以字节为元素的矩阵阵列表示,如图所示:
16字节明文按照此顺序放入矩阵,规则为:从上到下,从左到右,依次进行。
同样的,密钥K也需要分组,原理与明文P相同,下图为128位密钥矩阵:
下图为AES加密流程:
加密过程:C=E(K,P),其中C为加密后的密文,K为密钥,P为明文,E为加密函数。
解密过程:P=D(K,P),其中D为解密函数,解密过程为加密过程的逆运算。
AES的具体加密流程如下图所示:
AES加密过程通过四个步骤实现:字节替换、行移位、列混淆和轮密钥加。
注意: 根据密钥长度不同,加密的轮数也不同,在第一轮之前要进行轮密钥加,最后一轮没有进行列混淆操作。
我们来解释一下这四个步骤的具体含义:
字节替换: 属于非线性替换,具体原理就是通过一个替换表(S盒)对每个字节进行替换,实际上就是一个查表操作,并且此过程可逆,将每一个字节的前4位作为行值,后4位作为列值,去S盒查找,进行输出。
下图为S盒(x表示行,y表示列),例如字节为0x14,那么前四位的16进制为1,后四位的16进制为4,去查找s盒中的第1行第4列的值,可以看出为0xfa,就把原先的字节0x14替换为0xfa。
解密过程与此相同,唯一就是采用的是逆S盒。
接下来是行位移操作
对于4*4的矩阵,操作为:
第0行:保持不动;
第1行:循环左移1个字节;
第2行:循环左移2个字节;
第3行:循环左移3个字节。
解密过程变为循环右移,每行移动字节数与加密过程相同,下图为列位移示意图。
接下来是列混淆操作
实际上为44的矩阵与另一个44矩阵异或相乘(注意为右乘操作),重新得到一个4*4的矩阵,如下图所示。
解密过程为重新与此矩阵异或,因为两次异或得到的值为原数据本身。
最后为轮密钥加操作
轮密钥与状态矩阵进行逐比特异或操作。
这个轮密钥是由种子密钥通过密钥编排算法得到的,并且轮密钥长度与分组长度相同。
解密过程与之相同,两次异或得到原始数据。
密钥编排算法基本原则
1)轮密钥的比特数等于分组长度乘以轮数加1;
例如:将128位比特明文进行加密,总共需要(10+1)*128=1408比特密钥。
2)种子密钥扩展为扩展密钥;
3)轮密钥从扩展密钥中取,第一轮取扩展密钥的第0~3列,依次类推。
过程为:
定义:w[0]~w[3]为初始密钥
如果i=4的倍数,即i为每组的第一列,则执行以下3个步骤
1)将w[i-1]循环左移一个字节:
w[0] |
w[1] |
w[2] |
w[3] |
w[4] |
2b |
28 |
ab |
09 |
cf |
7e |
ae |
f7 |
cf |
4f |
15 |
d2 |
15 |
4f |
3c |
16 |
a6 |
88 |
3c |
09 |
w’[i]=w[i-1]左移一个字节得到。
w’[4]=w[3]左移一个字节得到={09,cf,4f,3c}左移一个字节={cf,4f,3c,09}
2)分别对w’[i]的每个字节进行S盒替换,本质上就是查表,再替换为另一个字节。
即查表后为w’‘[i]。
例如,w’[4]查表后的w’’[4]={8a,84,eb,01},需s盒的自行查看。
3)将前两步的结果同轮常量Rcon[j]进行异或,j表示轮数,Rcon[j]如下图所示
j |
1 |
2 |
3 |
4 |
5 |
Rcon[j] |
01 00 00 00 |
02 00 00 00 |
04 00 00 00 |
08 00 00 00 |
10 00 00 00 |
j |
6 |
7 |
8 |
9 |
10 |
Rcon[j] |
20 00 00 00 |
40 00 00 00 |
80 00 00 00 |
1B 00 00 00 |
36 00 00 00 |
那么w[i]=w[i-4]⊕w’[i]⊕Rcon[j],此时j=1,因为为第一轮。
即w[4]=w[0]⊕w’‘[4]⊕Rcon[1],
那么w[8]=w[4]⊕w’’[8]⊕Rcon[2],……
如果i≠4的倍数,即i为每组的第二、三、四列,则执行以下一个步骤
即w[i]=w[i-4]⊕w[i-1]
例如w[5]=w[1]⊕w[4],w[6]=w[2]⊕[5],……
最终的到一个扩展密钥:{w[4],w[5],w[6],w[7]},之后的每一轮密钥都是在前一轮基础上形成的。
可能说的不是很明白,后续将会补充。
相关链接(侵删)
- STM32 IAP升级AES256加密 应用及源码
- 【算法】【AES】加密算法详解
- C#调用dll提示”试图加载格式不正确的程序”原因及解决方法
- 解决 C# 调用DLL时 报“ 试图加载格式不正确的程序“(亲自验证)
- 解决64位dll“error LNK1561: 必须定义入口点”
- 1>LINK : fatal error LNK1561: 必须定义入口点
- C#中实现AES算法加密解读
- 用C#实现AES加密和解密
- AES加密算法详解(图文解释)
=================我是分割线=================
欢迎到公众号来唠嗑: