采用vs2010 + Crypto++(C++)

配置Crypto++

//0->0x30(48) 1->0x31(49) //将字符串转换为对应16进制数(一般是两位)string strToHex(string str){    stringstream ss;    ss << hex << setfill('0');    for(int i=0;i<str.size();i++){        // setw(2) 占两位,setfill('0') 空位填充 0        ss << setw(2) << (int)(unsigned char)str[i];    }    return ss.str();}
//0x30->0 0x31->1//将16进制数(一般两位为位为一个分割)转换为对应字符串string hexToStr(string hex){    string str;    for(string::size_type i = 0; i < hex.length(); i += 2) {        string tempStr = hex.substr(i, 2);        // string to int        unsigned char ch = (unsigned char)stoi(tempStr, nullptr, 16);        str.push_back(ch);    }    return str;}

PKCS5 是按 8 字节分组对数据进行填充的
AES 实际按 16 字节大小分组(PKCS5)
PKCS5 为 PKCS7 的一个子集
h<0x07><0x07><0x07><0x07><0x07><0x07><0x07> 7
he<0x06><0x06><0x06><0x06><0x06><0x06> 6
hel<0x05><0x05><0x05><0x05><0x05> 5
hell<0x04><0x04><0x04><0x04> 4
hello<0x03><0x03><0x03> 3
hello <0x02><0x02> 2
hello w<0x01> 1
hello wo<0x08><0x08><0x08><0x08><0x08><0x08><0x08><0x08> 8

// 分组后填充string padding(string plaintext){    string lastBlock;    int len = plaintext.length();    //16 - 最后一组长度    int paddingNum = AES::BLOCKSIZE - len % AES::BLOCKSIZE;    //完整组长度    int quotient = len / AES::BLOCKSIZE;    //获取最后一组长度    lastBlock = plaintext.substr(AES::BLOCKSIZE * quotient, len % AES::BLOCKSIZE);    //arr形如 hello <0x02><0x02>     for(int i = 0; i < AES::BLOCKSIZE - len % AES::BLOCKSIZE; i++) {        lastBlock.push_back((unsigned char)paddingNum);    }    return plaintext.substr(0, AES::BLOCKSIZE * quotient) + lastBlock;}
// 计数器自增 256进制 "123"+254=131string counterIncrement(string counter, int n){    string res = counter;    int addend = n;    for(int i = counter.length() - 1; i >= 0; i--) {        unsigned char tempChar = counter[i];        if((int)tempChar + addend > 255) {            tempChar = tempChar + addend;            addend = 1;        } else {            tempChar = tempChar + addend;            addend = 0;        }        res[i] = tempChar;    }    return res;}

CBC







CBC测试参数

CBC加密

string CBCencrypt(string plaintext, string key, string vi, string ciphertext){    plaintext = padding(plaintext);    //ciphertext为空 此时初始化为vi(用户设定为16位随机字符串)    ciphertext += vi;    key = hexToStr(key);    vi = hexToStr(vi);    //获取多少个组    int multiple = plaintext.length() / AES::BLOCKSIZE;    AESEncryption aesEncryptor;    aesEncryptor.SetKey((byte*)key.c_str(), key.length());        for(int i = 0; i < multiple; i++) {        string plaintextBlock = plaintext.substr(i * AES::BLOCKSIZE, AES::BLOCKSIZE);        string xorBlock;        //outblock存放一组的中间过程        unsigned char outBlock[AES::BLOCKSIZE];        memset(outBlock, 0, AES::BLOCKSIZE);                for(int j = 0; j < AES::BLOCKSIZE; j++) {            xorBlock.push_back(plaintextBlock[j] ^ (unsigned char)vi[j]);        }        aesEncryptor.ProcessBlock((byte*)xorBlock.c_str(), outBlock);        vi = "";        // unsigned char[] 转 string 不要通过这个方式:vi = (char *) outBlock        //outblock现在存放的是一组密文传递给vi        for(int j = 0; j < AES::BLOCKSIZE; j++) {            vi.push_back(outBlock[j]);        }        vi = vi.substr(0, AES::BLOCKSIZE);        ciphertext += strToHex(vi);    }    return ciphertext;}

CBC 解密

string CBCdecrypt(string ciphertext, string key, string vi,string plaintext){    // 原始 key 为 16 进制形式,需按字节转换为 char    key = hexToStr(key);    ciphertext = hexToStr(ciphertext);    // 随机生成16位 vi    //string vi = ciphertext.substr(0, AES::BLOCKSIZE);    ciphertext = ciphertext.substr(AES::BLOCKSIZE, ciphertext.length() - AES::BLOCKSIZE);    int multiple = ciphertext.length() / AES::BLOCKSIZE;    AESDecryption aesDecryptor;    aesDecryptor.SetKey((byte*)key.c_str(), key.length());    for(int i = 0; i < multiple; i++) {        // 分组密文 截取一组放入数组        string ciphertextBlock = ciphertext.substr(i * AES::BLOCKSIZE, AES::BLOCKSIZE);        unsigned char outBlock[AES::BLOCKSIZE];            memset(outBlock, 0, AES::BLOCKSIZE);        aesDecryptor.ProcessBlock((byte*)ciphertextBlock.c_str(), outBlock);        // AES 输出结果与上组密文或 vi 异或,得到明文        for(int j = 0; j < AES::BLOCKSIZE; j++) {            plaintext.push_back(outBlock[j] ^ (unsigned char)vi[j]);        }        vi = ciphertextBlock;    }    // 解密后,最后一组明文单独处理    string lastBlock = plaintext.substr((multiple - 1) * AES::BLOCKSIZE, AES::BLOCKSIZE);    // 从字符串最后一个字符获取填充字符    int paddingNum = (unsigned char)lastBlock[AES::BLOCKSIZE - 1];    // 把填充字符从明文中去掉    for(int i = 0; i < paddingNum; i++) {        // 若填充字符出现不同,则说明给定密文有误        if(plaintext.back() != paddingNum) {            return "Ciphertext is invalid!";        }        plaintext.pop_back();    }    return plaintext;}


CTR


CTR测试参数

CTR 加密

string CTRencrypt(string plaintext, string key, string counter, string ciphertext){    ciphertext += counter;    key = hexToStr(key);    counter = hexToStr(counter);    int multiple = plaintext.length() / AES::BLOCKSIZE;    AESEncryption aesEncryptor;    aesEncryptor.SetKey((byte*)key.c_str(), key.length());    for(int i = 0; i < multiple; i++) {        string plaintextBlock = plaintext.substr(i * AES::BLOCKSIZE, AES::BLOCKSIZE);        string xorBlock;        unsigned char outBlock[AES::BLOCKSIZE];        memset(outBlock, 0, AES::BLOCKSIZE);        aesEncryptor.ProcessBlock((byte*)counter.c_str(), outBlock);        for(int j = 0; j < AES::BLOCKSIZE; j++) {            xorBlock.push_back(outBlock[j] ^ (unsigned char)plaintextBlock[j]);        }        ciphertext += strToHex(xorBlock);        counter = counterIncrement(counter, 1);    }    int residueLen = plaintext.length() - multiple * AES::BLOCKSIZE;    string residuePlaintext = plaintext.substr(multiple * AES::BLOCKSIZE, residueLen);    string xorBlock;    unsigned char outBlock[AES::BLOCKSIZE];    memset(outBlock, 0, AES::BLOCKSIZE);    aesEncryptor.ProcessBlock((byte*)counter.c_str(), outBlock);    for(int j = 0; j < residueLen; j++) {        xorBlock.push_back(outBlock[j] ^ (unsigned char)residuePlaintext[j]);    }    ciphertext += strToHex(xorBlock);    return ciphertext;}

CTR 解密

string CTRdecrypt(string ciphertext,string counter, string key, string plaintext){    key = hexToStr(key);    ciphertext = hexToStr(ciphertext);            int multiple = ciphertext.length() / AES::BLOCKSIZE;    AESEncryption aesEncryptor;    aesEncryptor.SetKey((byte*)key.c_str(), key.length());    for(int i = 0; i < multiple; i++) {        string ciphertextBlock = ciphertext.substr(i * AES::BLOCKSIZE, AES::BLOCKSIZE);        string xorBlock;        unsigned char outBlock[AES::BLOCKSIZE];        memset(outBlock, 0, AES::BLOCKSIZE);        aesEncryptor.ProcessBlock((byte*)counter.c_str(), outBlock);        // 密文和 AES 加密结果异或,得到明文        for(int j = 0; j < AES::BLOCKSIZE; j++) {            xorBlock.push_back(outBlock[j] ^ (unsigned char)ciphertextBlock[j]);        }        plaintext += xorBlock;        // 计数器自增        counter = counterIncrement(counter, 1);    }    // 最后的分组可能不完整,单独输出 这里没有padding    int residueLen = ciphertext.length() - multiple * AES::BLOCKSIZE;    string residueCiphertext = ciphertext.substr(multiple * AES::BLOCKSIZE, residueLen);    string xorBlock;    unsigned char outBlock[AES::BLOCKSIZE];    memset(outBlock, 0, AES::BLOCKSIZE);    aesEncryptor.ProcessBlock((byte*)counter.c_str(), outBlock);    for(int j = 0; j < residueLen; j++) {        xorBlock.push_back(outBlock[j] ^ (unsigned char)residueCiphertext[j]);    }    plaintext += xorBlock;    return plaintext;}