Java 使用AES和大小为32的salt加密/解密
我必须创建一个weservice,它发送一个带有AES、salt大小为32和给定密码的加密字符串。我试图使我的代码正常工作,但当我尝试解密他们给我的字符串以检查解密是否正常工作时,我得到一个错误:Java 使用AES和大小为32的salt加密/解密,java,encryption,aes,Java,Encryption,Aes,我必须创建一个weservice,它发送一个带有AES、salt大小为32和给定密码的加密字符串。我试图使我的代码正常工作,但当我尝试解密他们给我的字符串以检查解密是否正常工作时,我得到一个错误: 线程“main”javax.crypto.BadPaddingException中的异常:给定的最后一个块没有正确填充 我的代码如下: import javax.crypto.*; import javax.crypto.spec.*; import java.security.*; import j
线程“main”javax.crypto.BadPaddingException中的异常:给定的最后一个块没有正确填充
我的代码如下:
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;
}
当我试图解密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();
}
}
}
private const int SaltSize=32;
///
///使用密钥解密密文。
///
///要解密的密文。
///纯文本加密密钥。
///解密的文本。
公共字符串解密(字符串密文、字符串密钥)
{
if(string.IsNullOrEmpty(密文))
抛出新的ArgumentNullException(“密文”);
if(string.IsNullOrEmpty(key))
抛出新的ArgumentNullException(“键”);
//从我们的密文中提取盐
var allTheBytes=Convert.fromBase64字符串(密文);
var saltBytes=allTheBytes.Take(SaltSize.ToArray();
var ciphertextBytes=allTheBytes.Skip(SaltSize).Take(allTheBytes.Length-SaltSize.ToArray();
使用(var keydrivationfunction=new Rfc2898DeriveBytes(key,saltBytes))
{
//从钥匙和盐中推导出上一个IV
var keyBytes=keydrivationfunction.GetBytes(32);
var ivBytes=keydrivationfunction.GetBytes(16);
//创建decrytor以执行流变换。
//创建用于解密的流。
//默认密码模式是CBC,填充是PKCS7,两者都很好
使用(var aesManaged=new aesManaged())
使用(var decryptor=aesManaged.CreateDecryptor(keyBytes,ivBytes))
使用(var memoryStream=新的memoryStream(ciphertextBytes))
使用(var cryptoStream=new cryptoStream(memoryStream、解密程序、CryptoStreamMode.Read))
使用(var streamReader=newstreamreader(cryptoStream))
{
//从解密流返回已解密的字节。
返回streamReader.ReadToEnd();
}
}
}
有什么提示吗?我已经运行了您的代码,您的原始字符串似乎有问题。您必须知道,如果使用128位密钥加密,则无法使用256位密钥加密。如果密钥大小不匹配,则会出现严重的填充错误。这是您的代码,其主要功能如下:
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!");
}
}
}
import java.security.NoSuchAlgorithmException;
导入java.security.NoSuchProviderException;
导入java.security.SecureRandom;
导入java.security.security;
导入java.security.spec.InvalidKeySpecException;
导入javax.crypto.Cipher;
导入javax.crypto.SecretKey;
导入javax.crypto.SecretKeyFactory;
导入javax.crypto.spec.IvParameterSpec;
导入javax.crypto.spec.PBEKeySpec;
导入javax.crypto.spec.SecretKeySpec;
导入org.bouncycastle.jce.provider.BouncyCastleProvider;
导入org.bouncycastle.util.encoders.Base64;
/**
*此代码的一部分是从中的StandardPByteEncryptor类复制的
*Jasypt(www.Jasypt.org)项目
*/
公共类七层密码{
//私有最终字符串密钥\u算法=“pbewithsha256和128bitaes-CBC-BC”;
私有最终字符串密钥_算法=“pbewithsha256和256基于CBC BC”;
私有最终字符串模式_PADDING=“/CBC/pkcs5ppadding”;
私有最终整数默认值\u SALT\u SIZE\u字节=32;
私人终审法院;
私有最终字符串passwd=“8g5qT74KdUY”;
public AESCrypt()引发异常{
rand=SecureRandom.getInstance(“SHA1PRNG”);
}
专用字节[]生成SALT(整数大小){
字节[]salt=新字节[大小];
兰特次字节(盐);
返盐;
}
私有SecretKey generateKey(字符串算法,int-keySize,字节[]salt)
抛出NoSuchProviderException、NoSuchAlgorithmException、,
InvalidKeySpecException{
SecretKeyFactory=SecretKeyFactory.getInstance(KEY\u算法);
PBEKeySpec PBEKeySpec=新的PBEKeySpec(passwd.toCharArray(),salt,
100000);
SecretKey tmpKey=factory.generateScret(pbeKeySpec);
byte[]keyBytes=新字节[keySize/8];
arraycopy(tmpKey.getEncoded(),0,keyBytes,0,keyBytes.length);
返回新的SecretKeySpec(keyBytes,算法);
}
专用字节[]生成IV(密码){
byte[]iv=新字节[cipher.getBlockSize()];
兰特下字节(四);
回报四;
}
专用字节[]追加数组(字节[]第一个数组,字节[]第二个数组){
最终字节[]结果=新字节[firstArray.length+secondArray.length];
数组复制(firstArray,0,result,0,firstArray.length);
System.arraycopy(secondArray,0,result,firstArray.length,
第二个数组(数组长度);
返回结果;
}
公共字节[]加密(字符串算法、整数密钥大小、最终字节[]消息)
抛出异常{
Cipher Cipher=Cipher.getInstance(算法+模式填充);
//所选算法的盐大小设置为相等
//到算法的块大小(如果是块算法)。
int saltSizeBytes=默认值\u SALT\u SIZE\u字节;
int algorithmBlockSize=cipher.getBlockSize();
如果(algorithmBlockSize>0){
saltSizeBytes=算法块大小;
}
//造盐
最后一个字节[]salt=生成salt(saltSizeBytes);
SecretKey=generateKey(算法、密钥大小、salt);
//为每个加密创建一个新的IV
最终IvParameterSpec ivParamSpec=新IvParameterSpec(
generateIV(密码);
//使用密码执行加密