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

来源:互联网 发布:软件应用商业计划书 编辑:程序博客网 时间:2024/06/05 05:40

问题描述

加密

输入:原始int数组,例如[1,2,3,4]
输出:加密后int数组,例如[2323,323,333,555]


解密

输入:加密后的int数组,例如[2323,323,333,555]
输出:解密后的int数组,例如[1,2,3,4]


一些解决方式

  • [OK] RSA算法对数组里面每个数字进行加解密
  • [NO] 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实现