简体   繁体   English

JAVA ANDROID AES CFB填充

[英]JAVA ANDROID AES CFB NOPADDING

I have created a Java file with following code that encrypt or decrypt a string: 我使用以下代码创建了一个Java文件,该代码对字符串进行加密或解密:

public class Aes {
public static String encrypt(String seed, String cleartext)
        throws Exception {
    byte[] rawKey = getRawKey(seed.getBytes());
    byte[] result = encrypt(rawKey, cleartext.getBytes());
    return toHex(result);
}

public static String decrypt(String seed, String encrypted)
        throws Exception {
    byte[] rawKey = getRawKey(seed.getBytes());
    byte[] enc = toByte(encrypted);
    byte[] result = decrypt(rawKey, enc);
    return new String(result);
}

private static byte[] getRawKey(byte[] seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    sr.setSeed(seed);
    kgen.init(128, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
}

private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
    byte[] iv = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF }; 
    IvParameterSpec ivSpec = new IvParameterSpec(iv);

    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
    byte[] encrypted = cipher.doFinal(clear);
    return encrypted;
}

private static byte[] decrypt(byte[] raw, byte[] encrypted)
        throws Exception {
    byte[] iv = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF }; 
    IvParameterSpec ivSpec = new IvParameterSpec(iv);

    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
    byte[] decrypted = cipher.doFinal(encrypted);
    return decrypted;
}

public static String toHex(String txt) {
    return toHex(txt.getBytes());
}

public static String fromHex(String hex) {
    return new String(toByte(hex));
}

public static byte[] toByte(String hexString) {
    int len = hexString.length() / 2;
    byte[] result = new byte[len];
    for (int i = 0; i < len; i++)
        result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
                16).byteValue();
    return result;
}

public static String toHex(byte[] buf) {
    if (buf == null)
        return "";
    StringBuffer result = new StringBuffer(2 * buf.length);
    for (int i = 0; i < buf.length; i++) {
        appendHex(result, buf[i]);
    }
    return result.toString();
}

private final static String HEX = "0123456789ABCDEF";

private static void appendHex(StringBuffer sb, byte b) {
    sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
}

I have success tried encrypt a string, but not to decrypt it back... please help me. 我已成功尝试加密字符串,但未将其解密...请帮助我。 This is example code to encrypt that I tested before: 这是我之前测试过的加密示例代码:

String data = "HELP";
String enc = "";
try {
enc = Aes.encrypt("1234567890", data);
Log.i("ENCRYPT", data + " TO " + enc);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

AND RESULT IS : 48F1880B 结果是:48F1880B

My question is, how to decrypt it? 我的问题是,如何解密? I was test using my code above but result not equal to plaintext! 我使用上面的代码进行了测试,但结果不等于纯文本! please help me... 请帮我...

The following example class should give you a good reference of how to encrypt/decrypt properly with all the steps labeled: 以下示例类应为您提供所有标记为步骤的正确加密/解密方法的良好参考:

public class AES {

    public static SecretKey generateAESKey(int bits) throws NoSuchAlgorithmException{
        //This method is provided as to securely generate a AES key of the given length.

        //In practice you can specify your own SecureRandom instance.
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(bits);
        return kgen.generateKey();
    }

    public static byte[] encrypt(SecretKey key, byte[] plaintext) throws Exception{
        //In practice you should specify your SecureRandom implementation.
        SecureRandom rnd = new SecureRandom();

        //Generate random IV of 128-bit (AES block size)
        byte[] IV = new byte[128 / 8]; 
        rnd.nextBytes(IV);
        IvParameterSpec IVSpec = new IvParameterSpec(IV);

        //Create the cipher object to perform AES operations.
        //Specify Advanced Encryption Standard - Cipher Feedback Mode - No Padding
        Cipher AESCipher = Cipher.getInstance("AES/CFB/NoPadding");

        //Initialize the Cipher with the key and initialization vector.
        AESCipher.init(Cipher.ENCRYPT_MODE, key, IVSpec);

        //Encrypts the plaintext data
        byte[] ciphertext = AESCipher.doFinal(plaintext);

       /*
        * The IV must now be transferred with the ciphertext somehow. The easiest 
        * way to accomplish this would be to prepend the IV to the ciphertext 
        * message.
        */

        //Allocate new array to hold ciphertext + IV
        byte[] output = new byte[ciphertext.length + (128 / 8)];

        //Copy the respective parts into the array.
        System.arraycopy(IV, 0, output, 0, IV.length);
        System.arraycopy(ciphertext, 0, output, IV.length, ciphertext.length);

        return output;
    }

    public static byte[] decrypt(SecretKey key, byte[] IV, byte[] ciphertext) throws Exception{
        //Create the cipher object to perform AES operations.
        //Specify Advanced Encryption Standard - Cipher Feedback Mode - No Padding
        Cipher AESCipher = Cipher.getInstance("AES/CFB/NoPadding");

        //Create the IvParameterSpec object from the raw IV
        IvParameterSpec IVSpec = new IvParameterSpec(IV);

        //Initialize the Cipher with the key and initialization vector.
        AESCipher.init(Cipher.DECRYPT_MODE, key, IVSpec);

        //Decrypts the ciphertext data
        byte[] plaintext = AESCipher.doFinal(ciphertext);

        return plaintext;
    }

    public static void main(String[] args) throws Exception{
        //Demo the program

        String sPlaintext = "rainbows"; //String plaintext
        byte[] rPlaintext = sPlaintext.getBytes(Charset.forName("UTF-8")); //Raw byte array plaintext

        //We first need to generate a key of 128-bit
        SecretKey key = generateAESKey(128);

        //Encrypt the plaintext
        byte[] output = encrypt(key, rPlaintext);

        // ----------------- //

        //Extract the IV from the encryption output
        byte[] IV = new byte[128 / 8];
        byte[] ciphertext = new byte[output.length - (128 / 8)];

        System.arraycopy(output, 0, IV, 0, IV.length);
        System.arraycopy(output, IV.length, ciphertext, 0, ciphertext.length);

        //Decrypt the ciphertext
        byte[] dPlaintext = decrypt(key, IV, ciphertext);

        String decryptedMessage = new String(dPlaintext, Charset.forName("UTF-8"));

        //Print stuff out
        System.out.println("Original message: " + sPlaintext);
        System.out.println("Original message bytes: " + Arrays.toString(rPlaintext));
        System.out.println("Encryption Output bytes: " + Arrays.toString(output));
        System.out.println("Decrypted message bytes: " + Arrays.toString(dPlaintext));
        System.out.println("Decrypted message: " + decryptedMessage);
    }
}

Few things to note however: 但是要注意的几件事:

throws Exception

is not acceptable. 是不能接受的。 This is only placed for the sake of simplifying code and should never be used in practice. 放置它只是为了简化代码,切勿在实践中使用。 Although some of those checked exceptions like NoSuchAlgorithmException is unlikely to be thrown please be wary that the decrypt() method will thrown exceptions for a failed decryption (ie bad key/IV/ciphertext). 尽管不大可能抛出诸如NoSuchAlgorithmException已检查异常,但请警惕decrypt()方法将为解密失败而抛出异常 (即,错误的密钥/ IV /密文)。

Leading onto my next point, you should not rely on the decrypt() method throwing exceptions as a way to validate input. 接下来我要讲的是,您不应该依赖引发异常的decrypt()方法来验证输入。 This should be one with a secure one-way hash function such as SHA-2 . 这应该是一种具有安全单向哈希函数的函数,例如SHA-2

Note how the key for encryption/decryption is generated once . 注意如何一次生成用于加密/解密的密钥。 AES is a symmetrical block cipher which means that the same key is used for both encryption and decryption . AES是对称的分组密码,这意味着加密和解密使用相同的密钥 Please keep note of that and not generate a new key between encryption and decryption (you can however generate a new key per encryption if you want, as long as you use the same key to decrypt). 请注意这一点,并且不要在加密和解密之间生成新的密钥 (但是,只要您愿意,只要使用相同的密钥进行解密,就可以为每个加密生成一个新的密钥)。

The problem is mainly in 问题主要在

public static String toHex(String txt) {
return toHex(txt.getBytes());
}

public static String fromHex(String hex) {
return new String(toByte(hex));
}

public static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
    result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
            16).byteValue();
return result;

while converting String from Hex String you are not converting them with leading zeroes ie when ever you are converting a char and the possible value of that char is zero then hex value is also 00 ,by default your method simply ignores the one zero and adds only one zero to the Hex String Hex String转换String ,您不会以前导零进行转换,即,无论何时转换char并且该char的可能值为零,则十六进制值也为00 ,默认情况下,您的方法将忽略一个零并仅添加十六进制字符串为零

Note:- The numerical zero 0 is not equal to the Hex value of Zero.Hex value of zero is a null character, refer the ASCII table. 注意:-数字零0不等于零的十六进制值。十六进制的零值为空字符,请参考ASCII表。

with leading Zeroes ef1b0030ef without leading zeroes ef1b030ef 带前导零 ef1b0030ef 不带前导零 ef1b030ef

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM