一丶AES五种加密模式说明
1、电码本模式(ECB)
将整个明文分成若干段相同的小段,然后对每一小段进行加密。
优点:操作简单,易于实现;分组独立,易于并行;误差不会被传送。——简单,可并行,不传送误差。
缺点:掩盖不了明文结构信息,难以抵抗统计分析攻击。——可对明文进行主动攻击。
2、密码分组链模式(CBC)
先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密。
优点:能掩盖明文结构信息,保证相同密文可得不同明文,所以不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL和IPSec的标准。
缺点:(1)不利于并行计算;(2)传递误差——前一个出错则后续全错;(3)第一个明文块需要与一个初始化向量IV进行抑或,初始化向量IV的选取比较复杂。
初始化IV的选取方式:固定IV,计数器IV,随机IV(只能得到伪随机数,用的最多),瞬时IV(难以得到瞬时值)
3、输出反馈模式(OFB)
密码算法的输出(指密码key而不是密文)会反馈到密码算法的输入中,OFB模式并不是通过密码算法对明文直接加密,而是通过将明文分组和密码算法的输出进行XOR来产生密文分组。
优点:隐藏了明文模式;结合了分组加密和流密码(分组密码转化为流模式);可以及时加密传送小于分组的数据。
缺点:不利于并行计算;需要生成秘钥流;对明文的主动攻击是可能的。
4、计数器模式(CTR)
完全的流模式。将瞬时值与计数器连接起来,然后对此进行加密产生密钥流的一个密钥块,再进行XOR操作 。
优点:不泄露明文;仅需实现加密函数;无需填充;可并行计算。
缺点:需要瞬时值IV,难以保证IV的唯一性。
5、密码反馈模式(CFB)
把分组密码当做流密码使用,即密码反馈模式可将DES分组密码置换成流密码。流密码具有密文和明文长度一致、运行实时的性质,这样数据可以在比分组小得多的单元里进行加密。如果需要发送的每个字符长为8比特,就应使用8比特密钥来加密每个字符。如果长度超过8比特,则造成浪费。但是要注意,由于CFB模式中分组密码是以流密码方式使用,所以加密和解密操作完全相同,因此无法适用于公钥密码系统,只能适用于对称密钥密码系统。
密码反馈模式也需要一个初始量,无须保密,但对每条消息必须有一个不同的初始量。
优点:可以处理任意长度的消息,能适应用户不同数据格式的需要。可实现自同步功能。就有有限步的错误传播,除能获得保密性外,还可用于认证。
缺点:对信道错误较敏感,且会造成错误传播。数据加密的速率被降低。
这里使用模式为: CBC模式
二丶前端代码如下:
1丶调用方法
// 引入加密包(注意存放的路径)
const Crypto = require('./crypto');
// 秘钥,转换成utf8格式字符串,用于加密解密,一般长度是16位(由后端提供)
const key = Crypto.enc.Utf8.parse('ffe5b4717179488a')
// 偏移量,转换成utf8格式字符串,一般长度是16位(由后端提供)
const iv = Crypto.enc.Utf8.parse('ffe5b4717179488b')
// 解密(使用CBC模式)
export function Decrtpt(value) {
// 使用外部包中的AES的解密方法
// value(解密内容)、key(密钥)
let decrypt = Crypto.AES.decrypt(value, key, {
iv, // 偏移量
mode: Crypto.mode.CBC, // 模式(五种加密模式,各有优缺)
padding: Crypto.pad.Pkcs7 // 填充
})
// 转成utf8格式字符串,并返回出去
let decryptedStr = decrypt.toString(Crypto.enc.Utf8)
return decryptedStr
}
//加密(使用CBC模式)
export function Encrypt(value) {
// 使用外部包中的AES的加密方法
// value(加密内容)、key(密钥)
let encrypt = Crypto.AES.encrypt(value, key, {
iv, // 偏移量
mode: Crypto.mode.CBC, // 模式(五种加密模式)
padding: Crypto.pad.Pkcs7 // 填充
})
// 将加密的内容转成字符串返回出去
return encrypt.toString()
}
// 导出密钥,以防其他地方需要使用
export const privateKey = 'ffe5b4717179488a'
2丶公共方法crypto.js内容
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS = CryptoJS || function (u, p) {
var d = {
}, l = d.lib = {
}, s = function () {
}, t = l.Base = {
extend: function (a) {
s.prototype = this; var c = new s; a && c.mixIn(a); c.hasOwnProperty("init") || (c.init = function () {
c.$super.init.apply(this, arguments) }); c.init.prototype = c; c.$super = this; return c }, create: function () {
var a = this.extend(); a.init.apply(a, arguments); return a }, init: function () {
}, mixIn: function (a) {
for (var c in a) a.hasOwnProperty(c) && (this[c] = a[c]); a.hasOwnProperty("toString") && (this.toString = a.toString) }, clone: function () {
return this.init.prototype.extend(this) } },
r = l.WordArray = t.extend({
init: function (a, c) {
a = this.words = a || []; this.sigBytes = c != p ? c : 4 * a.length }, toString: function (a) {
return (a || v).stringify(this) }, concat: function (a) {
var c = this.words, e = a.words, j = this.sigBytes; a = a.sigBytes; this.clamp(); if (j % 4) for (var k = 0; k < a; k++)c[j + k >>> 2] |= (e[k >>> 2] >>> 24 - 8 * (k % 4) & 255) << 24 - 8 * ((j + k) % 4); else if (65535 < e.length) for (k = 0; k < a; k += 4)c[j + k >>> 2] = e[k >>> 2]; else c.push.apply(c, e); this.sigBytes += a; return this }, clamp: function () {
var a = this.words, c = this.sigBytes; a[c >>> 2] &= 4294967295 <<
32 - 8 * (c % 4); a.length = u.ceil(c / 4)
}, clone: function () { var a = t.clone.call(this); a.words = this.words.slice(0); return a }, random: function (a) { for (var c = [], e = 0; e < a; e += 4)c.push(4294967296 * u.random() | 0); return new r.init(c, a) }
}), w = d.enc = {}, v = w.Hex = {
stringify: function (a) { var c = a.words; a = a.sigBytes; for (var e = [], j = 0; j < a; j++) { var k = c[j >>> 2] >>> 24 - 8 * (j % 4) & 255; e.push((k >>> 4).toString(16)); e.push((k & 15).toString(16)) } return e.join("") }, parse: function (a) {
for (var c = a.length, e = [], j = 0; j < c; j += 2)e[j >>> 3] |= parseInt(a.substr(j,
2), 16) << 24 - 4 * (j % 8); return new r.init(e, c / 2)
}
}, b = w.Latin1 = {
stringify: function (a) {
var c = a.words; a = a.sigBytes; for (var e = [], j = 0; j < a; j++)e.push(String.fromCharCode(c[j >>> 2] >>> 24 - 8 * (j % 4) & 255)); return e.join("") }, parse: function (a) {
for (var c = a.length, e = [], j = 0; j < c; j++)e[j >>> 2] |= (a.charCodeAt(j) & 255) << 24 - 8 * (j % 4); return new r.init(e, c) } }, x = w.Utf8 = {
stringify: function (a) {
try {
return decodeURIComponent(escape(b.stringify(a))) } catch (c) {
throw Error("Malformed UTF-8 data"); } }, parse: function (a) {
return b.parse(unescape(encodeURIComponent(a))) } },
q = l.BufferedBlockAlgorithm = t.extend({
reset: function () {
this._data = new r.init; this._nDataBytes = 0 }, _append: function (a) {
"string" == typeof a && (a = x.parse(a)); this._data.concat(a); this._nDataBytes += a.sigBytes }, _process: function (a) {
var c = this._data, e = c.words, j = c.sigBytes, k = this.blockSize, b = j / (4 * k), b = a ? u.ceil(b) : u.max((b | 0) - this._minBufferSize, 0); a = b * k; j = u.min(4 * a, j); if (a) { for (var q = 0; q < a; q += k)this._doProcessBlock(e, q); q = e.splice(0, a); c.sigBytes -= j } return new r.init(q, j) }, clone: function () {
var a = t.clone.call(this);
a._data = this._data.clone(); return a
}, _minBufferSize