gpt4 book ai didi

java - Java AES/CBC/PKCS5Padding 的 C# 加密/解密

转载 作者:行者123 更新时间:2023-11-30 01:58:40 26 4
gpt4 key购买 nike

我在尝试解密已使用以下属性(Java 代码)在 Java 中加密的字符串时遇到问题

public static Builder getDefaultBuilder(String key, String salt, byte[] iv) {
return new Builder()
.setIv(iv)
.setKey(key)
.setSalt(salt)
.setKeyLength(128)
.setKeyAlgorithm("AES")
.setCharsetName("UTF8")
.setIterationCount(1)
.setDigestAlgorithm("SHA1")
.setBase64Mode(Base64.DEFAULT)
.setAlgorithm("AES/CBC/PKCS5Padding")
.setSecureRandomAlgorithm("SHA1PRNG")
.setSecretKeyType("PBKDF2WithHmacSHA1");
}

这是我到目前为止的代码(C#)

public string DecryptText(string encryptedString)
{
using (myRijndael = new RijndaelManaged())
{
myRijndael.Key = Convert.FromBase64String(encryptionKey);
myRijndael.IV = new byte[16];
myRijndael.Mode = CipherMode.CBC;
myRijndael.Padding = PaddingMode.PKCS7;

Byte[] ourEnc = Convert.FromBase64String(encryptedString);
string ourDec = DecryptStringFromBytes(ourEnc, myRijndael.Key, myRijndael.IV);

return ourDec;
}
}

protected string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");

// Declare the string used to hold
// the decrypted text.
string plaintext = null;

// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;

// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{

// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}

}

return plaintext;

}

但是当我尝试解密时,出现以下异常“System.Security.Cryptography.CryptographyException:'指定的 key 不是此算法的有效大小。'”。

Java代码的起源就在这里 https://github.com/simbiose/Encryption/blob/master/Encryption/main/se/simbio/encryption/Encryption.java

这是加密时的Java代码

public String encrypt(String data) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidKeySpecException, BadPaddingException, IllegalBlockSizeException {
if (data == null) return null;
SecretKey secretKey = getSecretKey(hashTheKey(mBuilder.getKey()));
byte[] dataBytes = data.getBytes(mBuilder.getCharsetName());
Cipher cipher = Cipher.getInstance(mBuilder.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, secretKey, mBuilder.getIvParameterSpec(), mBuilder.getSecureRandom());
return Base64.encodeToString(cipher.doFinal(dataBytes), mBuilder.getBase64Mode());
}

private SecretKey getSecretKey(char[] key) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance(mBuilder.getSecretKeyType());
KeySpec spec = new PBEKeySpec(key, mBuilder.getSalt().getBytes(mBuilder.getCharsetName()), mBuilder.getIterationCount(), mBuilder.getKeyLength());
SecretKey tmp = factory.generateSecret(spec);
return new SecretKeySpec(tmp.getEncoded(), mBuilder.getKeyAlgorithm());
}


private char[] hashTheKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance(mBuilder.getDigestAlgorithm());
messageDigest.update(key.getBytes(mBuilder.getCharsetName()));
return Base64.encodeToString(messageDigest.digest(), Base64.NO_PADDING).toCharArray();
}

由于我并没有真正进行大量加密工作,因此我已经为此苦苦挣扎了两天,因此我们将不胜感激。

谢谢!

更新:全类

public sealed class MyCryptoClass
{
protected RijndaelManaged myRijndael;

private static string encryptionKey = "random";

// Singleton pattern used here with ensured thread safety
protected static readonly MyCryptoClass _instance = new MyCryptoClass();
public static MyCryptoClass Instance
{
get { return _instance; }
}

public MyCryptoClass()
{

}

public string DecryptText(string encryptedString)
{
using (myRijndael = new RijndaelManaged())
{
myRijndael.Key = Convert.FromBase64String(encryptionKey);
myRijndael.IV = new byte[16];
myRijndael.Mode = CipherMode.CBC;
myRijndael.Padding = PaddingMode.PKCS7;

Byte[] ourEnc = Convert.FromBase64String(encryptedString);
string ourDec = DecryptStringFromBytes(ourEnc, myRijndael.Key, myRijndael.IV);

return ourDec;
}
}


public string EncryptText(string plainText)
{
using (myRijndael = new RijndaelManaged())
{

myRijndael.Key = HexStringToByte(encryptionKey);
myRijndael.IV = HexStringToByte(initialisationVector);
myRijndael.Mode = CipherMode.CBC;
myRijndael.Padding = PaddingMode.PKCS7;

byte[] encrypted = EncryptStringToBytes(plainText, myRijndael.Key, myRijndael.IV);
string encString = Convert.ToBase64String(encrypted);

return encString;
}
}


protected byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;

// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{

//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}


// Return the encrypted bytes from the memory stream.
return encrypted;

}

protected string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");

// Declare the string used to hold
// the decrypted text.
string plaintext = null;

// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;

// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{

// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}

}

return plaintext;

}

public static void GenerateKeyAndIV()
{
// This code is only here for an example
RijndaelManaged myRijndaelManaged = new RijndaelManaged();
myRijndaelManaged.Mode = CipherMode.CBC;
myRijndaelManaged.Padding = PaddingMode.PKCS7;

myRijndaelManaged.GenerateIV();
myRijndaelManaged.GenerateKey();
string newKey = ByteArrayToHexString(myRijndaelManaged.Key);
string newinitVector = ByteArrayToHexString(myRijndaelManaged.IV);
}

protected static byte[] HexStringToByte(string hexString)
{
try
{
int bytesCount = (hexString.Length) / 2;
byte[] bytes = new byte[bytesCount];
for (int x = 0; x < bytesCount; ++x)
{
bytes[x] = Convert.ToByte(hexString.Substring(x * 2, 2), 16);
}
return bytes;
}
catch
{
throw;
}
}

public static string ByteArrayToHexString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
}

最佳答案

  • 自从您的 MyCryptoClass.encryptionKey对应于您的Encryption.Builder.mKey您必须在 C# 端生成 key ,即您必须在 C# 端为此过程中涉及的每个 Java 方法实现一个对应项。这些 Java 方法是 getSecretKey(char[] key) , hashTheKey(String key)还有third.part.android.util.Base64.encodeToString(byte[] input, int flags) .

  • 可能的 Java 方法的 C# 对应部分 getSecretKey(char[] key) :

    private static byte[] GetSecretKey()
    {
    string hashedKey = GetHashedKey();
    byte[] saltBytes = Encoding.UTF8.GetBytes(salt); // builder.mCharsetName = "UTF8";
    int iterations = 1; // builder.mIterationCount = 1
    byte[] secretKey = null;
    using (Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(hashedKey, saltBytes, iterations)) // builder.mSecretKeyType = "PBKDF2WithHmacSHA1";
    {
    secretKey = rfc2898.GetBytes(16); // builder.mKeyLength = 128;
    //Console.WriteLine("Key: " + ByteArrayToHexString(secretKey));
    }
    return secretKey;
    }

    此方法使用 PBKDF2WithHmacSHA1 派生 key 以 key 、盐、迭代次数和 key 长度作为输入。这里使用的 key (更准确地说是密码)是来自MyCryptoClass.encryptionKey的base64编码的SHA1哈希值。由GetHashedKey()提供(见下文)。

  • 可能的 Java 方法的 C# 对应部分 hashTheKey(String key) :

    private static string GetHashedKey()
    {
    string hashBase64 = String.Empty;
    using (SHA1Managed sha1 = new SHA1Managed()) // builder.mDigestAlgorithm = "SHA1";
    {
    byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(encryptionKey)); // builder.mCharsetName = "UTF8";
    hashBase64 = Base64ThirdPartAndroid(hash, true);
    //Console.WriteLine("Hash (base64): " + hashBase64);
    }
    return hashBase64;
    }

    此方法派生出 SHA1 -来自 MyCryptoClass.encryptionKey 的哈希值并对哈希值进行 Base64 编码。对于base64编码方法Base64ThirdPartAndroid(byte[] arr, bool withoutPadding) (见下文)被使用。

  • 可能的 Java 方法的 C# 对应部分 third.part.android.util.Base64.encodeToString(byte[] input, int flags) ( https://github.com/simbiose/Encryption/blob/master/Encryption/main/third/part/android/util/Base64.java ):

    private static string Base64ThirdPartAndroid(byte[] arr, bool withoutPadding)
    {
    string base64String = System.Convert.ToBase64String(arr);
    if (withoutPadding) base64String = base64String.TrimEnd('='); // Remove trailing "="-characters
    base64String += "\n"; // Append LF (10)
    //Console.WriteLine("Array as base64 encoded string: " + base64String);
    return base64String;
    }

    在Java代码中third.part.android.util.Base64.encodeToString(byte[] input, int flags)flags = Base64.NO_PADDING 一起使用它删除了 base64 编码字符串末尾的“=”字符。另外还附加了换行符(LF,\n,ASCII 值:10)。如果使用的 Base64 编码不删除“=”字符或没有终止换行符,则解密将失败,因为散列是稍后生成的 key 的基础,该 key 必须在加密和解密时匹配解密端。据我所知,C# 端没有具有必要特征的 Base64 编码。但是,如果有这样的编码,您当然可以使用它。

  • 将所有三个 C# 对应项添加到您的 MyCryptoClass class 中。

  • 另外(到静态字段 encryptionKey )添加静态字段 initialisationVector , saltsecretKey给您MyCryptoClass -class 并分配以下值用于测试目的:

    private static string encryptionKey = "A7zb534OPq59gU7q";
    private static string salt = "JV5k9GoH";
    private static byte[] initialisationVector = Encoding.UTF8.GetBytes("l4iG63jN9Dcg6537");
    private static byte[] secretKey = GetSecretKey();

    参数的类型对应于Java代码中的类型(encryptionKeysalt是字符串,initialisationVector是字节数组)。 GetSecretKey()生成的 key 存储在字节数组 secretKey 中.

  • 在你的 C# 中 DecryptText - 和EncryptText -方法集myRijndael.KeymyRijndael.IV

    myRijndael.Key = secretKey;
    myRijndael.IV = initialisationVector;
  • 按如下方式测试修改:

    • 使用您的 Java encrypt -方法加密以下纯文本:

      Test: The quick brown fox jumps over the lazy dog... 

      使用上面的 key/salt/iv

      mBuilder = Builder.getDefaultBuilder("A7zb534OPq59gU7q","JV5k9GoH","l4iG63jN9Dcg6537".getBytes("UTF-8"));
    • 加密后的文本为:

      mL4ajZtdRgD8CtGSfJGkT24Ebw4SrGUGKQI6bvBw1ziCO/J7SeLiyIw41zumTHMMD9GOYK+kR79CVcpoaHT9TQ==
    • 使用 C# 解密 DecryptText -方法再次给出纯文本。下面是两个测试用例:

      static void Main(string[] args)
      {
      // Test 1: Encrypted text from C#
      MyCryptoClass mcc = MyCryptoClass.Instance;
      string encryptedText = mcc.EncryptText("This is a plain text which needs to be encrypted...");
      Console.WriteLine("Encrypted text (base64): " + encryptedText);
      string decryptedText = mcc.DecryptText(encryptedText);
      Console.WriteLine("Decrypted text: " + decryptedText);

      // Test 2: Encrypted text from Java
      string javaEncryptedText = "mL4ajZtdRgD8CtGSfJGkT24Ebw4SrGUGKQI6bvBw1ziCO/J7SeLiyIw41zumTHMMD9GOYK+kR79CVcpoaHT9TQ==";
      Console.WriteLine("Encrypted text from Java (base64): " + javaEncryptedText);
      string javaDecryptedText = mcc.DecryptText(javaEncryptedText);
      Console.WriteLine("Decrypted text from Java: " + javaDecryptedText);
      }

关于java - Java AES/CBC/PKCS5Padding 的 C# 加密/解密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53580563/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com