javax.crypto.BadPaddingException AES

javax.crypto.BadPaddingException AES,java,android,encryption,aes,Java,Android,Encryption,Aes,我正在使用AESCrypt(gradle:compile'com.scottyab:AESCrypt:0.0.1') 对数据进行加密和解密 TextView tv=(TextView)findViewById(R.id.demotext); String encrypted="",decrypted=""; try { encrypted = AESCrypt.encrypt("password","This is the best thing to go

我正在使用
AESCrypt
(gradle:compile'com.scottyab:AESCrypt:0.0.1')
对数据进行加密和解密

  TextView  tv=(TextView)findViewById(R.id.demotext);
    String encrypted="",decrypted="";
    try {
        encrypted = AESCrypt.encrypt("password","This is the best thing to go by");

        decrypted = AESCrypt.decrypt("password",encrypted);
    } catch (GeneralSecurityException e) {
        e.printStackTrace();
    }
    System.out.println("EncryptedData:"+encrypted);
    System.out.println("DecryptedData:"+decrypted);
    tv.setText("Encrypted:"+encrypted +"\n"+"Decrypted:"+decrypted);
代码工作得非常好,在这种情况下,我得到的输入与解密文本相同

但是,当我尝试使用与屏幕截图所示相同的方法(AES)从站点使用已经加密的字符串时:

复制并粘贴加密文本,如:

decrypted = AESCrypt.decrypt("password","sttA+FbNm3RkTovjHI8CcAdStXiMl45s29Jqle+y+pA=");
然后运行代码,然后我得到一个错误消息:

javax.crypto.BadPaddingException: error:1e06b065:Cipher functions:EVP_DecryptFinal_ex:BAD_DECRYPT

但是当我在同一个网站上使用解密后的文本时,它可以正常工作,如下面的屏幕截图所示


可能是由于将密码短语“password”转换为SecretKeySpec的算法

这是AESCrypt中的算法

private static SecretKeySpec GenerateKey (final String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {    
     final MessageDigest digest = MessageDigest.getInstance (HASH_ALGORITHM);
     byte [] bytes = password.getBytes ("UTF-8");
     digest.update (bytes, 0, bytes.length);
     byte [] key = digest.digest ();

     log ("SHA-256 key" key);

     SecretKeySpec secretKeySpec = new SecretKeySpec (key, "AES");
     secretKeySpec return;
  }
这是(Java)示例aesencryption.net

sha = MessageDigest.getInstance ("SHA-1");
key = sha.digest (key);
key = Arrays.copyOf (key, 16); // Use only first 128 bit
SecretKey = new SecretKeySpec (key, "AES");
第一个应用SHA256哈希,第二个应用SHA-1,完成最多16个字节,因此密钥不同

我认为您正在以正确的方式加密和解密AES。你不需要改变任何事情

但是,如果希望与AESEncyption.net兼容,则需要实现相同的密钥生成算法。代码不太好。我试着总结一下

//Code from aesencryption.net 
// Generate key
MessageDigest sha = null;
key = myKey.getBytes ("UTF-8");
sha = MessageDigest.getInstance ("SHA-1");
key = sha.digest (key);
key = Arrays.copyOf (key, 16); // Use only first 128 bit
SecretKey = new SecretKeySpec (key, "AES");

public static String encrypt (String strToEncrypt) {
     Cipher cipher = Cipher.getInstance ("AES / ECB / PKCS5Padding");
     cipher.init (Cipher.ENCRYPT_MODE, SecretKey);
     Base64.encodeBase64String return (cipher.doFinal (strToEncrypt.getBytes ("UTF-8"))));
}

public static String decrypt (String strToDecrypt) {
     Cipher cipher = Cipher.getInstance ("AES / ECB / PKCS5PADDING");
     cipher.init (Cipher.DECRYPT_MODE, SecretKey);
     return new String (cipher.doFinal (Base64.decodeBase64 (strToDecrypt))));
}
我还可以提供从Android应用程序中提取的代码,该应用程序需要存储私人用户数据。数据使用受用户密码保护的AES密钥加密

public static String SIMMETRICAL_ALGORITHM = "AES";

//Generate cipher key with user provided password
private static String getPassphraseSize16(String key) {
    if (TextUtils.isEmpty(key)) {
        return null;
    }
    char controlChar = '\u0014';
    String key16 = key + controlChar;
    if (key16.length() < 16) {
        while (key16.length() < 16) {
            key16 += key + controlChar;
        }
    }
    if (key16.length() > 16) {
        key16 = key16.substring(key16.length() - 16, key16.length());
    }
    return key16;
}

//AES cipher with passphrase
public static byte[] encrypt(byte[] message, String passphrase)
        throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
    String passphrase16 = getPassphraseSize16(passphrase);

    SecretKeySpec secretKey = new SecretKeySpec(passphrase16.getBytes(), SIMMETRICAL_ALGORITHM);
    Cipher cipher = Cipher.getInstance(SIMMETRICAL_ALGORITHM);
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    byte[] encoded = cipher.doFinal(message);

    return encoded;
}

//AES decipher with passphrase
public static byte[] decrypt(byte[] encodedMessage, String key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
    String passphrase16 = getPassphraseSize16(key);

    SecretKeySpec secretKey = new SecretKeySpec(passphrase16.getBytes(), SIMMETRICAL_ALGORITHM);
    Cipher cipher = Cipher.getInstance(SIMMETRICAL_ALGORITHM);
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
    byte decoded[] = cipher.doFinal(encodedMessage);

    return decoded;
}
公共静态字符串SIMMETRICAL\u算法=“AES”;
//使用用户提供的密码生成密码密钥
私有静态字符串getPassphraseSize16(字符串密钥){
if(TextUtils.isEmpty(键)){
返回null;
}
char controlChar='\u0014';
字符串key16=key+controlChar;
if(键16.length()<16){
while(键16.length()<16){
键16+=键+控制字符;
}
}
如果(键16.length()>16){
key16=key16.substring(key16.length()-16,key16.length());
}
返回键16;
}
//带密码短语的AES密码
公共静态字节[]加密(字节[]消息,字符串密码)
抛出NoSuchPaddingException、NoSuchAlgorithmException、InvalidKeyException、BadPaddingException、IllegalBlockSizeException{
字符串passphrase16=getPassphraseSize16(passphrase);
SecretKeySpec secretKey=新的SecretKeySpec(passphrase16.getBytes(),SIMMETRICAL_算法);
Cipher Cipher=Cipher.getInstance(SIMMETRICAL_算法);
cipher.init(cipher.ENCRYPT_模式,secretKey);
字节[]编码=cipher.doFinal(消息);
返回编码;
}
//AES密码破译
公共静态字节[]解密(字节[]encodedMessage,字符串密钥)抛出NoSuchPaddingException、NoSuchAlgorithmException、InvalidKeyException、BadPaddingException、IllegalBlockSizeException{
字符串passphrase16=getPassphraseSize16(键);
SecretKeySpec secretKey=新的SecretKeySpec(passphrase16.getBytes(),SIMMETRICAL_算法);
Cipher Cipher=Cipher.getInstance(SIMMETRICAL_算法);
cipher.init(cipher.DECRYPT_模式,secretKey);
字节解码[]=cipher.doFinal(encodedMessage);
返回解码;
}

那么你的意思是我应该生成密钥并使用它,而不是直接使用?我认为你可以使用与示例中相同的方法来使用AESCrypt.encrypt和AESCrypt.decrypt,但它没有像我提到的那样工作?你能说清楚我应该修改什么吗?对不起,我的英语太差了。我在答案中总结了AES加密代码。依我看来,伊斯克里特是更好的选择。如果您想与aesencryption.net兼容,请直接使用其密钥生成代码(在aesencryption.net页面上已满),因为您知道自己在做什么,请使用测试代码编辑答案好吗?这将是最大的帮助。请不要将您编写的代码与您不知道其代码的在线加密机进行比较。你为什么会对这件事感兴趣?你所引用的网站很糟糕。它用两种不兼容的语言传播不太安全的代码。因为我想像1MB json一样加密并将其存储到Android Mobile。永远不要使用。它是确定性的,因此在语义上不安全。您至少应该使用随机模式,如或。最好是对密文进行身份验证,这样就不可能进行类似的攻击。这可以通过像GCM或EAX这样的认证模式来实现,也可以通过一个方案来实现
public static String SIMMETRICAL_ALGORITHM = "AES";

//Generate cipher key with user provided password
private static String getPassphraseSize16(String key) {
    if (TextUtils.isEmpty(key)) {
        return null;
    }
    char controlChar = '\u0014';
    String key16 = key + controlChar;
    if (key16.length() < 16) {
        while (key16.length() < 16) {
            key16 += key + controlChar;
        }
    }
    if (key16.length() > 16) {
        key16 = key16.substring(key16.length() - 16, key16.length());
    }
    return key16;
}

//AES cipher with passphrase
public static byte[] encrypt(byte[] message, String passphrase)
        throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
    String passphrase16 = getPassphraseSize16(passphrase);

    SecretKeySpec secretKey = new SecretKeySpec(passphrase16.getBytes(), SIMMETRICAL_ALGORITHM);
    Cipher cipher = Cipher.getInstance(SIMMETRICAL_ALGORITHM);
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    byte[] encoded = cipher.doFinal(message);

    return encoded;
}

//AES decipher with passphrase
public static byte[] decrypt(byte[] encodedMessage, String key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
    String passphrase16 = getPassphraseSize16(key);

    SecretKeySpec secretKey = new SecretKeySpec(passphrase16.getBytes(), SIMMETRICAL_ALGORITHM);
    Cipher cipher = Cipher.getInstance(SIMMETRICAL_ALGORITHM);
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
    byte decoded[] = cipher.doFinal(encodedMessage);

    return decoded;
}