java - 使用 AES 加密/解密,salt 大小为 32

标签 java encryption aes

我必须创建一个 weservice,它发送一个带有 AES、salt 大小为 32 和给定密码的加密字符串。我试图让我的代码正常工作,但是当我尝试解密他们给我的字符串以检查解密是否正常时,我收到错误消息:

Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded

我的代码如下:

import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.security.spec.InvalidKeySpecException;

/**
 * parts of this code were copied from the StandardPBEByteEncryptor class from the  Jasypt (www.jasypt.org) project
 */

public class AESCrypt {
    //private final String KEY_ALGORITHM = "PBEWITHSHA256AND128BITAES-CBC-BC";
    private final String KEY_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
    private final String MODE_PADDING = "/CBC/PKCS5Padding";
    private final int DEFAULT_SALT_SIZE_BYTES = 32;

    private final SecureRandom rand;

    private final String passwd = "8g5qT74KdUY";

    public AESCrypt() throws Exception {
    rand = SecureRandom.getInstance("SHA1PRNG");
}

private byte[] generateSalt(int size) {
    byte[] salt = new byte[size];
    rand.nextBytes(salt);

    return salt;
}

private SecretKey generateKey(String algorithm, int keySize, byte[] salt) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
    SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
    PBEKeySpec pbeKeySpec = new PBEKeySpec(passwd.toCharArray(), salt, 100000);
    SecretKey tmpKey = factory.generateSecret(pbeKeySpec);
    byte[] keyBytes = new byte[keySize / 8];
    System.arraycopy(tmpKey.getEncoded(), 0, keyBytes, 0, keyBytes.length);

    return new SecretKeySpec(keyBytes, algorithm);
}

private byte[] generateIV(Cipher cipher) {
    byte[] iv = new byte[cipher.getBlockSize()];
    rand.nextBytes(iv);

    return iv;
}

private byte[] appendArrays(byte[] firstArray, byte[] secondArray) {
    final byte[] result = new byte[firstArray.length + secondArray.length];

    System.arraycopy(firstArray, 0, result, 0, firstArray.length);
    System.arraycopy(secondArray, 0, result, firstArray.length, secondArray.length);

        return result;
}


public byte[] encrypt(String algorithm, int keySize, final byte[] message) throws Exception {
    Cipher cipher = Cipher.getInstance(algorithm + MODE_PADDING);

    // The salt size for the chosen algorithm is set to be equal
    // to the algorithm's block size (if it is a block algorithm).
    int saltSizeBytes = DEFAULT_SALT_SIZE_BYTES;
    int algorithmBlockSize = cipher.getBlockSize();
    if (algorithmBlockSize > 0) {
        saltSizeBytes = algorithmBlockSize;
    }

    // Create salt
    final byte[] salt = generateSalt(saltSizeBytes);

    SecretKey key = generateKey(algorithm, keySize, salt);

    // create a new IV for each encryption
    final IvParameterSpec ivParamSpec = new IvParameterSpec(generateIV(cipher));

    // Perform encryption using the Cipher
    cipher.init(Cipher.ENCRYPT_MODE, key, ivParamSpec);
    byte[] encryptedMessage = cipher.doFinal(message);

    // append the IV and salt
    encryptedMessage = appendArrays(ivParamSpec.getIV(), encryptedMessage);
    encryptedMessage = appendArrays(salt, encryptedMessage);

    return encryptedMessage;
}

public byte[] decrypt(String algorithm, int keySize, final byte[] encryptedMessage) throws Exception {
    Cipher cipher = Cipher.getInstance(algorithm + MODE_PADDING);

    // determine the salt size for the first layer of encryption
    int saltSizeBytes = DEFAULT_SALT_SIZE_BYTES;
    int algorithmBlockSize = cipher.getBlockSize();
    if (algorithmBlockSize > 0) {
        saltSizeBytes = algorithmBlockSize;
    }
    System.out.println("saltSizeBytes:"+saltSizeBytes);

    byte[] decryptedMessage = new byte[encryptedMessage.length];
    System.arraycopy(encryptedMessage, 0, decryptedMessage, 0, encryptedMessage.length);

    // extract the salt and IV from the incoming message
    byte[] salt = null;
    byte[] iv = null;
    byte[] encryptedMessageKernel = null;
    final int saltStart = 0;
    final int saltSize = (saltSizeBytes < decryptedMessage.length ? saltSizeBytes : decryptedMessage.length);
    //final int saltSize = 32;
    //System.out.println("saltSize:"+saltSize);

    final int ivStart = (saltSizeBytes < decryptedMessage.length ? saltSizeBytes : decryptedMessage.length);
    final int ivSize = cipher.getBlockSize();
    final int encMesKernelStart = (saltSizeBytes + ivSize < decryptedMessage.length ? saltSizeBytes + ivSize : decryptedMessage.length);
    final int encMesKernelSize = (saltSizeBytes + ivSize < decryptedMessage.length ? (decryptedMessage.length - saltSizeBytes - ivSize) : 0);

    salt = new byte[saltSize];
    iv = new byte[ivSize];
    System.out.println("saltSize:"+saltSize);
    System.out.println("ivSize:"+ivSize);

    encryptedMessageKernel = new byte[encMesKernelSize];
    System.out.println("encryptedMessageKernel");

    System.arraycopy(decryptedMessage, saltStart, salt, 0, saltSize);
    System.arraycopy(decryptedMessage, ivStart, iv, 0, ivSize);
    System.arraycopy(decryptedMessage, encMesKernelStart, encryptedMessageKernel, 0, encMesKernelSize);

    SecretKey key = generateKey(algorithm, keySize, salt);
    System.out.println("ekey");

    IvParameterSpec ivParamSpec = new IvParameterSpec(iv);

    // Perform decryption using the Cipher
    cipher.init(Cipher.DECRYPT_MODE, key, ivParamSpec);
    decryptedMessage = cipher.doFinal(encryptedMessageKernel);

    // Return the results
    return decryptedMessage;
}

现在我有了这个信息,我知道它是加密的,我想解密:

Original String: 12334567
 Crypted String: SsH6NO9a64g0U7szvFwSbCkdUF5dNgmxgpt2jU/nFVntG3r2nYxgxLRXri4MW9Z2
       Password: 8g5qT74KdUY

当我尝试解密 SsH... 时,我得到了给定的错误。哪里有问题?这就是我所做的:

String toDecrypt = "SsH6NO9a64g0U7szvFwSbCkdUF5dNgmxgpt2jU/nFVntG3r2nYxgxLRXri4MW9Z2"; 
byte[] criptata = Base64.decode(toDecrypt); 
byte[] decriptata = engine.decrypt("AES", 128, criptata);
String msgdecriptato = new String(decriptata); 

这给了我一个错误。

这是他们用来解密的 C# 代码:

private const int SaltSize = 32;

/// <summary>
///     Decrypts the ciphertext using the Key.
/// </summary>
/// <param name="ciphertext">The ciphertext to decrypt.</param>
/// <param name="key">The plain text encryption key.</param>
/// <returns>The decrypted text.</returns>
public  string Decrypt(string ciphertext, string key)
{
        if (string.IsNullOrEmpty(ciphertext))
            throw new ArgumentNullException("ciphertext");
        if (string.IsNullOrEmpty(key))
            throw new ArgumentNullException("key");

        // Extract the salt from our ciphertext
        var allTheBytes = Convert.FromBase64String(ciphertext);
        var saltBytes = allTheBytes.Take(SaltSize).ToArray();
        var ciphertextBytes = allTheBytes.Skip(SaltSize).Take(allTheBytes.Length - SaltSize).ToArray();

        using (var keyDerivationFunction = new Rfc2898DeriveBytes(key, saltBytes))
        {
            // Derive the previous IV from the Key and Salt
            var keyBytes = keyDerivationFunction.GetBytes(32);
            var ivBytes = keyDerivationFunction.GetBytes(16);

            // Create a decrytor to perform the stream transform.
            // Create the streams used for decryption.
            // The default Cipher Mode is CBC and the Padding is PKCS7 which are both good
            using (var aesManaged = new AesManaged())
            using (var decryptor = aesManaged.CreateDecryptor(keyBytes, ivBytes))
            using (var memoryStream = new MemoryStream(ciphertextBytes))
            using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
            using (var streamReader = new StreamReader(cryptoStream))
            {
                // Return the decrypted bytes from the decrypting stream.
                return streamReader.ReadToEnd();
            }
        }
    }

有什么提示吗?

最佳答案

我已经运行了您的代码,您的原始字符串似乎有问题。您必须知道,如果它是用 128 位 key 加密的,则不能用 256 位 key 加密。如果 key 大小不匹配,则会出现错误的填充错误。这是你的代码,有一个 main 有效:

import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;

/**
 * parts of this code were copied from the StandardPBEByteEncryptor class from
 * the Jasypt (www.jasypt.org) project
 */

public class AESCrypt {
    // private final String KEY_ALGORITHM = "PBEWITHSHA256AND128BITAES-CBC-BC";
    private final String KEY_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
    private final String MODE_PADDING = "/CBC/PKCS5Padding";
    private final int DEFAULT_SALT_SIZE_BYTES = 32;

    private final SecureRandom rand;

    private final String passwd = "8g5qT74KdUY";

    public AESCrypt() throws Exception {
        rand = SecureRandom.getInstance("SHA1PRNG");
    }

    private byte[] generateSalt(int size) {
        byte[] salt = new byte[size];
        rand.nextBytes(salt);

        return salt;
    }

    private SecretKey generateKey(String algorithm, int keySize, byte[] salt)
            throws NoSuchProviderException, NoSuchAlgorithmException,
            InvalidKeySpecException {
        SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
        PBEKeySpec pbeKeySpec = new PBEKeySpec(passwd.toCharArray(), salt,
                100000);
        SecretKey tmpKey = factory.generateSecret(pbeKeySpec);
        byte[] keyBytes = new byte[keySize / 8];
        System.arraycopy(tmpKey.getEncoded(), 0, keyBytes, 0, keyBytes.length);

        return new SecretKeySpec(keyBytes, algorithm);
    }

    private byte[] generateIV(Cipher cipher) {
        byte[] iv = new byte[cipher.getBlockSize()];
        rand.nextBytes(iv);

        return iv;
    }

    private byte[] appendArrays(byte[] firstArray, byte[] secondArray) {
        final byte[] result = new byte[firstArray.length + secondArray.length];

        System.arraycopy(firstArray, 0, result, 0, firstArray.length);
        System.arraycopy(secondArray, 0, result, firstArray.length,
                secondArray.length);

        return result;
    }

    public byte[] encrypt(String algorithm, int keySize, final byte[] message)
            throws Exception {
        Cipher cipher = Cipher.getInstance(algorithm + MODE_PADDING);

        // The salt size for the chosen algorithm is set to be equal
        // to the algorithm's block size (if it is a block algorithm).
        int saltSizeBytes = DEFAULT_SALT_SIZE_BYTES;
        int algorithmBlockSize = cipher.getBlockSize();
        if (algorithmBlockSize > 0) {
            saltSizeBytes = algorithmBlockSize;
        }

        // Create salt
        final byte[] salt = generateSalt(saltSizeBytes);

        SecretKey key = generateKey(algorithm, keySize, salt);

        // create a new IV for each encryption
        final IvParameterSpec ivParamSpec = new IvParameterSpec(
                generateIV(cipher));

        // Perform encryption using the Cipher
        cipher.init(Cipher.ENCRYPT_MODE, key, ivParamSpec);
        byte[] encryptedMessage = cipher.doFinal(message);

        // append the IV and salt
        encryptedMessage = appendArrays(ivParamSpec.getIV(), encryptedMessage);
        encryptedMessage = appendArrays(salt, encryptedMessage);

        return encryptedMessage;
    }

    public byte[] decrypt(String algorithm, int keySize,
            final byte[] encryptedMessage) throws Exception {
        Cipher cipher = Cipher.getInstance(algorithm + MODE_PADDING);

        // determine the salt size for the first layer of encryption
        int saltSizeBytes = DEFAULT_SALT_SIZE_BYTES;
        int algorithmBlockSize = cipher.getBlockSize();
        if (algorithmBlockSize > 0) {
            saltSizeBytes = algorithmBlockSize;
        }
        System.out.println("saltSizeBytes:" + saltSizeBytes);

        byte[] decryptedMessage = new byte[encryptedMessage.length];
        System.arraycopy(encryptedMessage, 0, decryptedMessage, 0,
                encryptedMessage.length);

        // extract the salt and IV from the incoming message
        byte[] salt = null;
        byte[] iv = null;
        byte[] encryptedMessageKernel = null;
        final int saltStart = 0;
        final int saltSize = (saltSizeBytes < decryptedMessage.length ? saltSizeBytes
                : decryptedMessage.length);
        // final int saltSize = 32;
        // System.out.println("saltSize:"+saltSize);

        final int ivStart = (saltSizeBytes < decryptedMessage.length ? saltSizeBytes
                : decryptedMessage.length);
        final int ivSize = cipher.getBlockSize();
        final int encMesKernelStart = (saltSizeBytes + ivSize < decryptedMessage.length ? saltSizeBytes
                + ivSize
                : decryptedMessage.length);
        final int encMesKernelSize = (saltSizeBytes + ivSize < decryptedMessage.length ? (decryptedMessage.length
                - saltSizeBytes - ivSize)
                : 0);

        salt = new byte[saltSize];
        iv = new byte[ivSize];
        System.out.println("saltSize:" + saltSize);
        System.out.println("ivSize:" + ivSize);

        encryptedMessageKernel = new byte[encMesKernelSize];
        System.out.println("encryptedMessageKernel");

        System.arraycopy(decryptedMessage, saltStart, salt, 0, saltSize);
        System.arraycopy(decryptedMessage, ivStart, iv, 0, ivSize);
        System.arraycopy(decryptedMessage, encMesKernelStart,
                encryptedMessageKernel, 0, encMesKernelSize);

        SecretKey key = generateKey(algorithm, keySize, salt);
        System.out.println("ekey");

        IvParameterSpec ivParamSpec = new IvParameterSpec(iv);

        // Perform decryption using the Cipher
        cipher.init(Cipher.DECRYPT_MODE, key, ivParamSpec);
        decryptedMessage = cipher.doFinal(encryptedMessageKernel);

        // Return the results
        return decryptedMessage;
    }

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        AESCrypt aesCrypt = new AESCrypt();
        String originalText = "1234567";
        String toDecrypt = new String(Base64.encode(aesCrypt.encrypt("AES", 256, originalText.getBytes())));
        System.out.println(toDecrypt);

        byte[] criptata = Base64.decode(toDecrypt); 
        byte[] decriptata = aesCrypt.decrypt("AES", 256, criptata);
        String msgdecriptato = new String(decriptata); 
        System.out.println(msgdecriptato);
        if (!originalText.equals(msgdecriptato)) {
            throw new IllegalStateException("Strings do not match!");
        }
    }

}

关于java - 使用 AES 加密/解密,salt 大小为 32,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13684602/

相关文章:

c# - 加密 Unity c# 标注到 Node js 服务器

c# - .NET CORE 中的 "Specified cipher mode is not valid for this algorithm"但在 .NET Standard 中工作

android - 在 Android 中使用 AES/CBC/PKCS5Padding 进行不正确的解密

node.js - 在 Node.js 中获取 256 位 AES GCM 加密的正确标签时遇到问题

java - Tomcat 和 Web 服务

php - 我应该如何在 PHP 应用程序中加密我的数据?

java - 更改 IBM WebSphere Message Broker 节点属性

php openssl_decrypt() 参数(之前由 perl Crypt::CBC 加密)

java - 谷歌应用程序数据存储区中的外键

JAVA移动设备-本地存储数据