問題の説明
暗号化
入力:[1,2,3,4]などの元のint配列
出力:[2323,323,333,555]などの暗号化されたint配列
graph LR
1,2,3,4-->2323,323,333,555
復号化
入力:[2323,323,333,555]などの暗号化されたint配列
出力:[1,2,3,4]などの復号化されたint配列
graph LR
2323,323,333,555-->1,2,3,4
いくつかの解決策
- RSAアルゴリズムは、配列内の各番号を暗号化および復号化します
- AESは、最初に各番号を文字列に変換し、次にそれを暗号化および復号化します。暗号化された文字列をデジタル表現に変換できないため、この方法は機能しません。
AESソリューション
javaコードでは、jdkは独自のライブラリを使用してキーを自動的に生成し、それをファイルに保存します。C++で使用される暗号化ライブラリはcryptであり、非常に強力な暗号化ライブラリであり、配列はベクターコンテナに置き換える必要があります。
ステップ1int変換バイト
intは4バイトに対応し、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;
}
ステップ2バイト整数
4バイトは1Intに対応し、変換コードは次のとおりです。
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;
}
ステップ3バイト配列と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]);
}
バイト配列は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));
}
}
ステップ4バイト配列を暗号化および復号化するための最後のステップ
ここでは、AESモードの選択を検討する必要があります。int配列にintが1つしかない場合、それは長い間4バイトに相当し、16バイトのaesの長さを満たしません。暗号化された合計の長さが暗号化前の長さと同じであることを願っています。長さが同じである場合、暗号化後の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 ++はcryptlibを含むVS2015プロジェクトです。アドレスは次のとおりです。AESint配列暗号化JavaC ++の実装