密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。
简介
这个标准用来替代原先的DES(Data Encryption Standard),已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院 (NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一 [1]。
该算法为比利时密码学家Joan Daemen和Vincent Rijmen所设计,结合两位作者的名字,以Rijdael之名命之,投稿高级加密标准的甄选流程。(Rijdael的发音近于 "Rhine doll"。)
剖析
高级加密标准算法从很多方面解决了令人担忧的问题。实际上,攻击数据加密标准的那些手段对于高级加密标准算法本身并没有效果。如果采用真正的128位加密技术甚至256位加密技术,蛮力攻击要取得成功需要耗费相当长的时间。
虽然高级加密标准也有不足的一面,但是,它仍是一个相对新的协议。因此,安全研究人员还没有那么多的时间对这种加密方法进行破解试验。我们可能会随时发现一种全新的攻击手段会攻破这种高级加密标准。至少在理论上存在这种可能性。
AES加密模式
对称/分组密码一般分为流加密(如OFB、CFB等)和块加密(如ECB、CBC等)。对于流加密,需要将分组密码转化为流模式工作。对于块加密(或称分组加密),如果要加密超过块大小的数据,就需要涉及填充和链加密模式。
ECB(Electronic Code Book电子密码本)模式
ECB模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密。
优点:
1.简单; 2.有利于并行计算; 3.误差不会被传送; 缺点: 1.不能隐藏明文的模式; 2.可能对明文进行主动攻击; 因此,此模式适于加密小消息。
CBC(Cipher Block Chaining,加密块链)模式
优点:
1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。 缺点: 1.不利于并行计算; 2.误差传递; 3.需要初始化向量IV
CFB(Cipher FeedBack Mode,加密反馈)模式
优点:
1.隐藏了明文模式; 2.分组密码转化为流模式; 3.可以及时加密传送小于分组的数据; 缺点: 1.不利于并行计算; 2.误差传送:一个明文单元损坏影响多个单元; 3.唯一的IV;
OFB(Output FeedBack,输出反馈)模式
优点:
1.隐藏了明文模式; 2.分组密码转化为流模式; 3.可以及时加密传送小于分组的数据; 缺点: 1.不利于并行计算; 2.对明文的主动攻击是可能的; 3.误差传送:一个明文单元损坏影响多个单元 [4]。
鸿蒙加密
首先引用 import cryptoFramework from '@ohos.security.cryptoFramework' 在cryptoFramework 创建 createSymKeyGenerator(通过指定算法名称的字符串,获取相应的对称密钥生成器实例。) 本例以AES 256为准。
注:AES 256的key和iv 都是32位为准 如果是AES 128的key 和 iv 是16位。
AES 256 加密 实例如下:
/*** 加密* @param key* @param source*/encrypt(source: String, key: string, iv: string): Promise<String> {let cipherAlgName = 'AES256|CBC|PKCS7';let symKeyGenerator = cryptoFramework.createSymKeyGenerator(AES256);let ivParam: cryptoFramework.IvParamsSpec = {iv: { data: SecurityCommon.stringToUint8Array(iv, 32) },algName: "IvParamsSpec"}let cipher;return new Promise((resolve, reject) => {symKeyGenerator.convertKey({ data: SecurityCommon.stringToUint8Array(iv, 32) }).then(symKey => {try {cipher = cryptoFramework.createCipher(cipherAlgName)console.info(`xx cipher algName: ${cipher.algName}`)} catch (error) {console.error(`xx createCipher failed, ${error.code}, ${error.message}`);return null}//创建cipher之后才能初始化return cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, ivParam).then(() => {//创建cipher且初始化之后才能执行doFinalreturn cipher.doFinal({data: SecurityCommon.stringToUint8Array(source)})}).then(output => {let base64 = new util.Base64Helper();let result = base64.encodeToStringSync(output.data);return new Promise((resolve) => {resolve(result)})}).catch(e => {return new Promise((_, reject) => {reject(e)})})}).catch(e => {return new Promise((_, reject) => {reject(e)})}).then(result => {resolve(result)})})}
鸿蒙解密
首先引用 import cryptoFramework from '@ohos.security.cryptoFramework' 在cryptoFramework 创建 createSymKeyGenerator(通过指定算法名称的字符串,获取相应的对称密钥生成器实例。) 本例以AES 256为准。
注:AES 256的key和iv 都是32位为准 如果是AES 128的key 和 iv 是16位。
AES 256 解密 实例如下:
/*** aes 解密* @param message* @param key* @param iv* @param callback*/decrypt(message: string, key: string, iv: string): Promise<String> {let cipherAlgName = 'AES256|CBC|PKCS7';let symKeyGenerator = cryptoFramework.createSymKeyGenerator(AES256);let ivParam: cryptoFramework.IvParamsSpec = {iv: { data: SecurityCommon.stringToUint8Array(iv, 32) },algName: "IvParamsSpec"}let cipher;return new Promise((resolve, reject) => {return symKeyGenerator.convertKey({data: SecurityCommon.stringToUint8Array(iv, 32)}).then(symKey => {try {cipher = cryptoFramework.createCipher(cipherAlgName);console.info(`xx cipher algName: ${cipher.algName}`);} catch (error) {console.error(`xx createCipher failed, ${error.code}, ${error.message}`);return null}return cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, ivParam).then(() => {let base64 = new util.Base64Helper();let result = base64.decodeSync(message);return cipher.doFinal({data: result})}).then(output => {let result = SecurityCommon.uint8ArrayToString(output.data)return new Promise((resolve) => {resolve(result)})}).catch(e => {return new Promise((_, reject) => {reject(e)})})}).catch(e => {reject(e)}).then(result => {resolve(result)})})}
字符串转无符号字节数组(Uint8Array)的方法
/*** 把String 转换为Uint8 数组* @param str* @returns*/stringToUint8Array(str, len = null): Uint8Array {let arr = [];if (len == null) {len = str.length}for (let i = 0; i < len; i++) {if (str.length > i) {arr.push(str.charCodeAt(i))} else {arr.push(0)}}return new Uint8Array(arr);}
无符号字节数组 转换为字符串
uint8ArrayToString(array: Uint8Array) {let arrayString = '';for (let i = 0; i < array.length; i++) {arrayString += String.fromCharCode(array[i]);}return arrayString;}