C++ 和 java 使用 AES CBC 128 加解密

Java 使用jce, code:


import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Arrays;


//import org.apache.commons.codec.binary.Base64;


public class Encryptor {


    /**
     * 字符串转换成十六进制字符串
     */
    public static String str2HexStr(String str) {


        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
        }
        return sb.toString();
    }


    /**
     *
     * 十六进制转换字符串
     */


    public static byte[] hexStr2Bytes(String hexStr) {
        System.out.println("in len :" + hexStr.length());
        String str = "0123456789ABCDEF";
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int n;
        for (int i = 0; i < bytes.length; i++) {
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xff);
        }
        System.out.println("out len :" + bytes.length);
        System.out.println("ddd" + Arrays.toString(bytes));
        return bytes;
    }


    /**
     * bytes转换成十六进制字符串
     */
    public static String byte2HexStr(byte[] b) {
        String hs = "";
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = (Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1)
                hs = hs + "0" + stmp;
            else
                hs = hs + stmp;
            // if (n<b.length-1) hs=hs+":";
        }
        return hs.toUpperCase();
    }


    public static String encrypt(String key, String initVector, String value) {
        try {
            System.out.println("key:\t" + Arrays.toString(key.getBytes("UTF-8")));
            System.out.println("iv:\t" + Arrays.toString(initVector.getBytes("UTF-8")));
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");


            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            //Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);


            byte[] encrypted = cipher.doFinal(value.getBytes());
            System.out.println(Arrays.toString(encrypted));
            //System.out.println("encrypted string: "
            //        + Base64.encodeBase64String(encrypted));


            return byte2HexStr(encrypted);
            //return Base64.encodeBase64String(encrypted);
        } catch (Exception ex) {
            ex.printStackTrace();
        }


        return null;
    }


    public static String decrypt(String key, String initVector, String encrypted) {
        try {
            IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
            SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");


            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);


            //byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
            byte[] original = cipher.doFinal(hexStr2Bytes(encrypted));


            return new String(original);
        } catch (Exception ex) {
            ex.printStackTrace();
        }


        return null;
    }


    public static void main(String[] args) {
        String key = "1234567890123456"; // 128 bit key
        String initVector = "0000000000000000"; // 16 bytes IV


        String en = encrypt(key, initVector, "hello world, cryptopp");
        System.out.println(en);
        System.out.println(decrypt(key, initVector, en));
    }
}


编译运行输出


➜  cypherTest javac Encryptor.java
➜  cypherTest java Encryptor
key:    [49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54]
iv:    [48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48]
[2, -46, -51, -100, 37, -49, 11, 72, -29, -122, -15, -49, -44, -40, -17, -69, -14, -69, -112, -20, -124, 98, -8, 108, -88, 33, 23, 19, -66, 3, -48, -59]
02D2CD9C25CF0B48E386F1CFD4D8EFBBF2BB90EC8462F86CA8211713BE03D0C5
in len :64
out len :32
ddd[2, -46, -51, -100, 37, -49, 11, 72, -29, -122, -15, -49, -44, -40, -17, -69, -14, -69, -112, -20, -124, 98, -8, 108, -88, 33, 23, 19, -66, 3, -48, -59]
hello world, cryptopp


C++ 使用cryptopp库(https://www.cryptopp.com/  下载后,make&& make install 编译安装)


#ifndef CRYPTOPP_H
#define CRYPTOPP_H


#include <iostream>
#include <fstream>
#include <sstream>


#include <cryptopp/aes.h>
#include <cryptopp/filters.h>
#include <cryptopp/modes.h>






class cryptopp {
public:
    static bool init(const std::string& key, const std::string& iv);
    static std::string encrypt(const std::string& inputPlainText);
    static std::string decrypt(const std::string& cipherTextHex);
private:
    static byte s_key[CryptoPP::AES::DEFAULT_KEYLENGTH];
    static byte s_iv[CryptoPP::AES::DEFAULT_KEYLENGTH];
};
#endif


#include "cryptopp.h"


using namespace std;


void print(const string& cipherText) {
    cout << "[";
    for( unsigned int i = 0; i < cipherText.size(); i++ )
    {
        cout << int(cipherText[i]) << ", "  ;
    }
    cout << "]"<< endl;
}


byte cryptopp::s_key[CryptoPP::AES::DEFAULT_KEYLENGTH];
byte cryptopp::s_iv[CryptoPP::AES::DEFAULT_KEYLENGTH];


bool cryptopp::init(const string& key, const string& iv) {
    if (key.size() != CryptoPP::AES::DEFAULT_KEYLENGTH) {
        return false;
    }
    if (iv.size() != CryptoPP::AES::BLOCKSIZE) {
        return false;
    }


    for(int i = 0; i < CryptoPP::AES::DEFAULT_KEYLENGTH; i++) {
        s_key[i] = key[i];
    }
    for(int i = 0; i < CryptoPP::AES::BLOCKSIZE; i++) {
        s_iv[i] = iv[i];
    }
    //memset(s_key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH);
    //memset(s_iv, 0x00, CryptoPP::AES::BLOCKSIZE);
    return true;
}






string cryptopp::encrypt(const string& plainText)
{
    /*
    if ((plainText.length() % CryptoPP::AES::BLOCKSIZE) != 0) {
        return "";
    }
    */


    string cipherTextHex;
    try {
        string cipherText;
        CryptoPP::AES::Encryption aesEncryption(s_key, CryptoPP::AES::DEFAULT_KEYLENGTH);
        CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption( aesEncryption, s_iv);
        //CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink( cipherText ), CryptoPP::StreamTransformationFilter::NO_PADDING);
        CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink( cipherText ));
        stfEncryptor.Put( reinterpret_cast<const unsigned char*>( plainText.c_str() ), plainText.length() );
        stfEncryptor.MessageEnd();


        print(cipherText);
        for( unsigned int i = 0; i < cipherText.size(); i++ )
        {
            char ch[3] = {0};
            sprintf(ch, "%02x",  static_cast<byte>(cipherText[i]));
            cipherTextHex += ch;
        }
    } catch (const std::exception &e) {
        cipherTextHex = "";
    }


    return cipherTextHex;
}


string cryptopp::decrypt(const string& cipherTextHex)
{
    /*
    if(cipherTextHex.empty()) {
        return string();
    }
    if ((cipherTextHex.length() % CryptoPP::AES::BLOCKSIZE) != 0) {
        return string();
    }
    */


    string cipherText;
    string decryptedText;


    unsigned int i = 0;
    while(true)
    {
        char c;
        int x;
        stringstream ss;
        ss<<hex<<cipherTextHex.substr(i, 2).c_str();
        ss>>x;
        c = (char)x;
        cipherText += c;
        if(i >= cipherTextHex.length() - 2)break;
        i += 2;
    }


    try {
        CryptoPP::AES::Decryption aesDecryption(s_key, CryptoPP::AES::DEFAULT_KEYLENGTH);
        CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, s_iv );
        //CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedText ),CryptoPP::StreamTransformationFilter::NO_PADDING);
        CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedText ));
        stfDecryptor.Put( reinterpret_cast<const unsigned char*>( cipherText.c_str() ), cipherText.size());


        stfDecryptor.MessageEnd();
    } catch (const std::exception &e) {
        decryptedText = "";
    }


    return decryptedText;
}


int main() {
    cryptopp::init("1234567890123456", "0000000000000000");
    string en = cryptopp::encrypt("hello world, cryptopp");
    cout << en << endl;
    cout << cryptopp::decrypt(en) << endl;
}


编译 g++ cryptopp.cpp -lcryptopp

运行输出

$./a.out
[2, -46, -51, -100, 37, -49, 11, 72, -29, -122, -15, -49, -44, -40, -17, -69, -14, -69, -112, -20, -124, 98, -8, 108, -88, 33, 23, 19, -66, 3, -48, -59, ]
02d2cd9c25cf0b48e386f1cfd4d8efbbf2bb90ec8462f86ca8211713be03d0c5
hello world, cryptopp


### 回答1: AES(Advanced Encryption Standard)是一种对称加密算法,CBC(Cipher Block Chaining)是一种加密模式,128表示密钥长度为128位。 在AES CBC 128加密过程中,首先需要一个128位的密钥,用来加密和解密数据。加密过程中,数据被分成一块一块的固定长度(通常是128位)进行处理。每一块数据会与前一块数据进行异或操作,然后再使用密钥进行加密。第一块数据需要初始化向量(IV)与之进行异或操作。 整个加密过程按块进行,每一块数据的加密都依赖于前一块数据的加密结果,这样可以增加加密的强度。解密过程与加密过程相反,需要使用相同的密钥和初始化向量。 AES CBC 128加解密算法具有较高的安全性和效率。由于使用CBC模式,数据块之间的关系变得复杂,最后一块的加密结果也会影响前面块的解密结果,提高了数据的安全性。 AES CBC 128加解密适用于多种场景,例如数据传输、文件加密等。在实际应用中,需要确保密钥的安全性,避免密钥被泄露,从而保证加解密的安全性。 需要注意的是,加密算法本身并不能完全保证数据的绝对安全,只是提供了一种加密方式来增加数据的安全性。为了更好地保护数据,还需要综合考虑其他因素,如密钥管理、访问控制等。 综上所述,AES CBC 128加解密是一种强大的加密算法,通过使用128位的密钥和CBC模式,能够提供较高的安全性和效率,广泛应用于数据保护领域。 ### 回答2: AES(Advanced Encryption Standard)是一种常用的对称加密算法,其中CBC(Cipher Block Chaining)是其一种工作模式。128代表AES算法的密钥长度为128位。 在使用AES CBC 128进行加密时,首先需要选择一个128位的密钥。然后,将明文分成若干个128位的块,并对每个块进行加密处理。在CBC模式下,每个块的加密依赖于前一个加密块的密文,这一点与ECB(Electronic Codebook)模式不同。 在加密过程中,首先将第一个块与初始向量(Initialization Vector,IV)进行异或运算,然后再使用密钥对其进行加密得到第一个密文块。接下来,将第二个明文块与第一个密文块进行异或运算,再使用密钥对其进行加密得到第二个密文块。以此类推,对每个明文块都进行类似的处理。 在解密过程中,首先使用密钥对第一个密文块进行解密,得到第一个明文块。然后将第一个密文块与解密后的第一个明文块进行异或运算,得到第二个明文块。再使用密钥对第二个密文块进行解密,得到原本的第二个明文块。以此类推,对每个密文块都进行类似的处理。 需要注意的是,在使用AES CBC 128进行加解密时,需要保证具有相同密钥和初始向量。初始向量在加解密过程中起到了一定的随机性作用,提高了密文的安全性。 总结来说,AES CBC 128是一种采用128位密钥长度的AES加密算法的工作模式,通过使用CBC模式和异或运算,对明文进行分块加密或解密,从而保障数据的保密性和完整性。它被广泛应用于信息安全领域中,用于保护敏感数据的传输和存储。 ### 回答3: AES(Advanced Encryption Standard)是一种常用的对称加密算法,其中CBC(Cipher Block Chaining)是其中一种模式。AES CBC 128加解密指的是使用128位的密钥对数据进行加解密,并采用CBC模式。 在AES CBC 128加密中,首先需要选择一个128位的密钥。然后,将待加密的数据分为若干个128位的数据块,每个数据块之间进行异或运算。接下来,使用AES算法对每个数据块进行加密运算。对于第一个数据块,将其与初始化向量(IV)进行异或运算,然后使用密钥进行加密。对于后续的数据块,将其与前一个加密后的数据块进行异或运算,然后再使用密钥进行加密。最后,将加密后的数据块按顺序拼接起来,得到最终的密文。 解密过程与加密过程相反。首先,将密文拆分为128位的数据块。对于第一个数据块,使用密钥进行解密,然后与IV进行异或运算得到明文。对于后续的数据块,先使用密钥进行解密,再与前一个解密后的数据块进行异或运算,得到明文。 AES CBC 128加解密在保证数据机密性的同时,还能够提供数据完整性和抵御重放攻击的能力。这是因为每个数据块都与前一个数据块相关联,并且每个数据块都使用了相同的密钥进行加密和解密,从而使得攻击者无法轻易修改其中一个数据块而不影响后续数据块的解密结果。 总结起来,AES CBC 128加解密是一种常用的对称加密算法,能够在保证数据机密性的同时提供数据完整性和抵御重放攻击的能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值