问题描述
加密
输入:原始int数组,例如[1,2,3,4]
输出:加密后int数组,例如[2323,323,333,555]
graph LR
1,2,3,4-->2323,323,333,555
解密
输入:加密后的int数组,例如[2323,323,333,555]
输出:解密后的int数组,例如[1,2,3,4]
graph LR
2323,323,333,555-->1,2,3,4
一些解决方式
- RSA算法对数组里面每个数字进行加解密
- AES先把每个数字转换成字符串,然后进行加密和解密。这种方法不行,因为加密后的字符串不能转换成数字表示。
AES的解决方式
java代码是jdk采用自带库,会自动生成密钥,然后我们就保存在文件中;C++采用的加密库是crypt,很强大的加密库,数组应用vector容器来替代。
Step 1 int转byte
一个int对应4个byte,java转换代码如下:
public static byte[] int2byte(int res) {
byte[] targets = new byte[4];
targets[0] = (byte) (res & 0xff);
targets[1] = (byte) ((res >> 8) & 0xff);
targets[2] = (byte) ((res >> 16) & 0xff);
targets[3] = (byte) (res >>> 24);
return targets;
}
C++转换代码如下:
byte* EncryptAES::int2byte(int res) {
byte *targets = new byte[4];
targets[0] = (byte)(res & 0xff);
targets[1] = (byte)((res >> 8) & 0xff);
targets[2] = (byte)((res >> 16) & 0xff);
targets[3] = (byte)((int)((unsigned)res >> 24));
return targets;
}
Step 2 byte转int
4个byte对应1个Int,转换代码如下:
public static int byte2int(byte[] res) {
int targets = (res[0] & 0xff) | ((res[1] << 8) & 0xff00)
| ((res[2] << 24) >>> 8) | (res[3] << 24);
return targets;
}
C++转换代码如下:
nt EncryptAES::byte2int(vector<byte> res) {
int targets = (res[0] & 0xff) | ((res[1] << 8) & 0xff00)
| (int)((unsigned)(res[2] << 24) >> 8) | (res[3] << 24);
return targets;
}
Step 3 byte数组和int数组之间的相互转换
int数组转换成byte数组,java转换代码如下:
public static byte[] ints2byte(int res[]) {
byte[] a = new byte[res.length * 4]; //预分配4*int数组的大小
for (int i = 0; i < res.length; i++) {
byte temp[] = int2byte(res[i]);
System.arraycopy(temp, 0, a, i * 4, 4);
}
return a;
}
C++转换代码如下:
void EncryptAES::ints2byte(vector<int> res, vector<byte> &a) {
for (int i = 0; i < res.size(); i++) {
byte* temp = EncryptAES::int2byte(res[i]);
for (int j = 0;j < 4;j++) {
a.push_back(temp[j]);
}
byte数组转换成int数组,java转换代码如下:
public static int[] byte2ints(byte[] res) {
byte[] byte_3 = null;
byte_3 = new byte[res.length];
System.arraycopy(res, 0, byte_3, 0, res.length);
int[] result = new int[byte_3.length / 4]; //预分配byte数组的大小
for (int i = 0; i < byte_3.length; i = i + 4) {
byte b[] = new byte[4];
System.arraycopy(byte_3, i, b, 0, 4);
result[i / 4] = byte2int(b);
}
return result;
}
C++转换代码如下:
void EncryptAES::byte2ints(vector<byte> res, vector<int> &results) {
vector<byte> c;
for (int i = 0; i < res.size(); i = i + 4) {
c.clear();
for (int j = 0;j < 4;j++) {
c.push_back(res[i + j]);
}
results.push_back(byte2int(c));
}
}
Step 4 最后一步加密和解密byte数组
这里我们就要考虑AES的模式选择了,如果一个int数组只有一个int,那么久相当于只有4个字节,不满足aes的16个字节的长度,我们希望加密和的长度和加密之前的长度一样,那么加密后的int个数和加密之前的int个数相同,所以我们选择AES/OFB/NoPadding模式。至于aes所有的模式如下图:
java加密和解密代码如下:
public static int[] encrypt(int input[]) {
encrypt(ints2byte(input));
return byte2ints(result);
}
public static int[] decrypt(int input[], String str) {
byte[] a = new byte[input.length * 4];
byte[] res = ints2byte(input);
System.arraycopy(res, 0, a, 0, res.length);
decrypt(a, str);
return byte2ints(result);
}
public static String getSecretKey() throws IOException {
File file = new File("key");
byte[] key = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
fis.read(key);
String str = new String(key, "ISO-8859-1");
return str;
}
public static void encrypt(byte[] bobo) {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
SecretKey secretKey = keyGenerator.generateKey();
IvParameterSpec paramSpec = new IvParameterSpec(AES_IV);
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec aesKey = new SecretKeySpec(enCodeFormat, "AES");
File file = new File("key");
OutputStream outputStream = new FileOutputStream(file);
outputStream.write(enCodeFormat);
outputStream.flush();
outputStream.close();
Cipher cipher = Cipher.getInstance("AES/OFB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, aesKey, paramSpec);
result = cipher.doFinal(bobo);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void decrypt(byte[] bobo, String str) {
try {
byte[] key = str.getBytes("ISO-8859-1");
SecretKeySpec aesKey = new SecretKeySpec(key, "AES");
IvParameterSpec paramSpec = new IvParameterSpec(AES_IV);
Cipher cipher = Cipher.getInstance("AES/OFB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, aesKey, paramSpec);
result = cipher.doFinal(bobo);
} catch (Exception e) {
e.printStackTrace();
}
}
C++加密和解密代码如下:
void EncryptAES::encrypt(vector<int> input, vector<int> &res) {
vector<byte> temp;
ints2byte(input, temp);
AesEncrypt(temp);
byte2ints(result, res);
}
void EncryptAES::decrypt(vector<int> input, string str, vector<int> &res2) {
vector<byte> a;
vector<byte> res;
ints2byte(input, res);
for (int i = 0;i < res.size();i++)
a.push_back(res[i]);
AesDecrypt(a, str);
byte2ints(result, res2);
}
string EncryptAES::getSecretKey(string Path) {
ifstream infile;
infile.open(Path.c_str(), ios::binary);
if (!infile)
{
return "没有秘钥文件";
}
infile.seekg(0, ios::end);
unsigned long len = infile.tellg();
byte* buffer = new byte[len];
infile.seekg(0, ios::beg);
infile.read((char*)buffer, len);
infile.close();
string encoded;
encoded.clear();
StringSource(buffer, len, true,
new HexEncoder(
new StringSink(encoded)
) // HexEncoder
); // StringSource
delete[](buffer);
return encoded;
}
void EncryptAES::AesEncrypt(vector<byte> a) {
try
{
string cipher;
AutoSeededRandomPool prng;
byte key[AES::DEFAULT_KEYLENGTH];
prng.GenerateBlock(key, sizeof(key));
ofstream outputF("aeskey", ofstream::binary);
for (int i = 0;i<AES::DEFAULT_KEYLENGTH;i++)
outputF << key[i];
outputF.flush();
outputF.close();
OFB_Mode< AES >::Encryption e;
e.SetKeyWithIV(key, sizeof(key), AES_IV);
byte* plain = new byte[a.size()];
for (int i = 0;i < a.size();i++)
plain[i] = a[i];
// OFB mode must not use padding. Specifying
// a scheme will result in an exception
StringSource(plain, a.size(), true,
new StreamTransformationFilter(e,
new StringSink(cipher)
) // StreamTransformationFilter
); // StringSource
result.clear();
vector<byte>(result).swap(result);
stringToByte(cipher, result);
delete[]plain;
}
catch (const CryptoPP::Exception& e)
{
cerr << e.what() << endl;
exit(1);
}
}
void EncryptAES::AesDecrypt(vector<byte> a, string str) {
string decoded;
StringSource ss(str, true,
new HexDecoder(
new StringSink(decoded)
) // HexDecoder
); // StringSource
vector<byte> keyTemp;
stringToByte(decoded, keyTemp);
byte* key = new byte[keyTemp.size()];
for (int i = 0;i < keyTemp.size();i++)
key[i] = keyTemp[i];
byte* cipher = new byte[a.size()];
for (int i = 0;i < a.size();i++)
cipher[i] = a[i];
try
{
string recovered;
OFB_Mode< AES >::Decryption d;
d.SetKeyWithIV(key, keyTemp.size(), AES_IV);
// The StreamTransformationFilter removes
// padding as required.
StringSource s(cipher, a.size(), true,
new StreamTransformationFilter(d,
new StringSink(recovered)
) // StreamTransformationFilter
); // StringSource
result.clear();
vector<byte>(result).swap(result);
stringToByte(recovered, result);
delete[](key);
delete[](cipher);
}
catch (const CryptoPP::Exception& e)
{
cerr << e.what() << endl;
exit(1);
}
}
工程代码实现
Java是IDEA工程,C++是VS2015工程,包含crypt lib。地址如下:AES int数组加密 Java C++s实现