Skip to content

CryptoJS源码与实现原理分析

核心架构

1. 基础数据结构

javascript
// WordArray是CryptoJS的核心数据结构
const WordArray = C_lib.WordArray = Base.extend({
    init: function (words, sigBytes) {
        // words是32位字的数组
        words = this.words = words || [];
        
        // sigBytes表示有效字节数
        this.sigBytes = sigBytes != undefined ? sigBytes : words.length * 4;
    },
    
    // 转换为字符串
    toString: function (encoder) {
        return (encoder || Hex).stringify(this);
    }
});

2. 类继承体系

javascript
// Base对象提供继承机制
var Base = C_lib.Base = (function () {
    return {
        // 创建新对象
        extend: function (overrides) {
            // 原型继承
            var subtype = create(this);
            
            // 复制属性
            if (overrides) {
                subtype.mixIn(overrides);
            }
            
            return subtype;
        },
        
        // 创建实例
        create: function () {
            var instance = this.extend();
            instance.init.apply(instance, arguments);
            return instance;
        }
    };
}());

AES算法实现流程

1. 密钥扩展

javascript
// 密钥扩展过程
_doReset: function () {
    // 1. 获取原始密钥
    var key = this._key;
    var keyWords = key.words;
    
    // 2. 计算轮密钥
    var ksRows = this._keySchedule = [];
    for (var ksRow = 0; ksRow < nRounds + 1; ksRow++) {
        // 使用Rijndael密钥扩展算法
        if (ksRow < keySize) {
            ksRows[ksRow] = keyWords[ksRow];
        } else {
            t = ksRows[ksRow - 1];
            
            if (!(ksRow % keySize)) {
                // 密钥置换
                t = (t << 8) | (t >>> 24);
                t = (SBOX[t >>> 24] << 24) | 
                    (SBOX[(t >>> 16) & 0xff] << 16) |
                    (SBOX[(t >>> 8) & 0xff] << 8) |
                    SBOX[t & 0xff];
                t ^= RCON[(ksRow / keySize) | 0] << 24;
            }
            
            ksRows[ksRow] = ksRows[ksRow - keySize] ^ t;
        }
    }
}

2. 加密主要步骤

javascript
// 加密一个数据块
encryptBlock: function (M, offset) {
    // 1. 初始轮密钥加
    this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0,
        SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX);
},

_doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0,
        SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) {
    
    // 2. 字节替换(SubBytes)
    // 使用S-box进行非线性变换
    for (var row = 0; row < 4; row++) {
        for (var col = 0; col < 4; col++) {
            state[row][col] = SBOX[state[row][col]];
        }
    }
    
    // 3. 行移位(ShiftRows)
    // 循环左移不同的位数
    for (var row = 1; row < 4; row++) {
        state[row] = circularLeftShift(state[row], row);
    }
    
    // 4. 列混合(MixColumns)
    // GF(2^8)上的矩阵乘法
    for (var col = 0; col < 4; col++) {
        mixColumn(state, col);
    }
    
    // 5. 轮密钥加(AddRoundKey)
    // 与轮密钥异或
    for (var row = 0; row < 4; row++) {
        for (var col = 0; col < 4; col++) {
            state[row][col] ^= roundKey[row][col];
        }
    }
}

工作模式实现

1. CBC模式

javascript
// CBC模式实现
CBC: BlockCipherMode.extend({
    // 加密
    encryptBlock: function (words, offset) {
        // 1. 获取IV或上一个密文块
        var iv = this._iv;
        
        // 2. 明文块与IV异或
        for (var i = 0; i < blockSize; i++) {
            words[offset + i] ^= iv[i];
        }
        
        // 3. 加密
        this._cipher.encryptBlock(words, offset);
        
        // 4. 更新IV
        this._iv = words.slice(offset, offset + blockSize);
    }
})

2. ECB模式

javascript
// ECB模式实现
ECB: BlockCipherMode.extend({
    // 加密
    encryptBlock: function (words, offset) {
        this._cipher.encryptBlock(words, offset);
    }
})

填充机制

PKCS7填充

javascript
// PKCS7填充实现
pad: function (data, blockSize) {
    // 1. 计算需要填充的字节数
    var paddingSize = blockSize - (data.sigBytes % blockSize);
    
    // 2. 创建填充数组
    var paddingWords = [];
    for (var i = 0; i < paddingSize; i++) {
        paddingWords.push(paddingSize);
    }
    
    // 3. 连接数据
    return data.concat(WordArray.create(paddingWords));
}

性能优化原理

1. 查表优化

javascript
// 预计算的S-box表
var SBOX = [];
var INV_SBOX = [];
var SUB_MIX_0 = [];
var SUB_MIX_1 = [];
var SUB_MIX_2 = [];
var SUB_MIX_3 = [];

// 初始化查找表
(function () {
    // 生成S-box和逆S-box
    var d = [];
    for (var i = 0; i < 256; i++) {
        var q = ((i & 0x80) ? 0x1b : 0) ^ (i << 1);
        d[i] = q;
        SBOX[i] = // 计算S-box值
        INV_SBOX[SBOX[i]] = i;
    }
    
    // 生成混合列查找表
    for (var i = 0; i < 256; i++) {
        SUB_MIX_0[i] = (d[i] << 24) | (i << 16) | (i << 8) | d[i];
        SUB_MIX_1[i] = (i << 24) | (d[i] << 16) | (i << 8) | i;
        SUB_MIX_2[i] = (i << 24) | (i << 16) | (d[i] << 8) | i;
        SUB_MIX_3[i] = (i << 24) | (i << 16) | (i << 8) | d[i];
    }
}());

2. 位运算优化

javascript
// 使用位运算代替乘法
function mixColumn(state, col) {
    var s0 = state[0][col];
    var s1 = state[1][col];
    var s2 = state[2][col];
    var s3 = state[3][col];
    
    // 使用查表和异或运算代替GF(2^8)乘法
    state[0][col] = SUB_MIX_0[s0 >>> 24] ^
                    SUB_MIX_1[(s1 >>> 16) & 0xff] ^
                    SUB_MIX_2[(s2 >>> 8) & 0xff] ^
                    SUB_MIX_3[s3 & 0xff];
}

面试重点

  1. WordArray设计思想

    • 为什么使用32位字数组
    • sigBytes的作用
    • 与TypedArray的区别
  2. AES核心步骤

    • 密钥扩展原理
    • 四个变换的数学原理
    • 为什么是这些特定操作
  3. 性能优化技巧

    • 查表优化的原理
    • 位运算的应用s
    • 内存管理策略
  4. 安全性保证

    • 各个工作模式的安全特性
    • 填充oracle攻击的防范
    • 密钥管理的最佳实践

参考资源