AES加解密int数组——Java C++实现

问题描述

加密

输入:原始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所有的模式如下图:

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实现

猜你喜欢

转载自blog.csdn.net/u012397189/article/details/75090065