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