簡體   English   中英

C# AES 加密到 java 8 解密

[英]C# AES encrypt to java 8 decrypt

我試圖在 C# 中模擬 Java 加密例程,因為端點是基於 Java 的,並且將解密 C# 生成的值。

我已經嘗試了使用AesCryptoServiceProviderAesManaged從 SO 和網絡上的幾個示例中找到的不同實現,但我仍然無法讓 java 端點成功解密該值,它出現錯誤{"message":"AUTHENTICATION_ERROR: Error while decrypting the cipher.","status":"Error"}

使用郵遞員,我能夠調用 java 端點並使用下面發布的 java 代碼生成的加密文本檢索文檔,因此該部分得到了肯定的驗證。

端點使用標頭值解密文本並驗證內容,以下是相關代碼片段:

java加密

  private static Cipher generateCipher(int mode, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
    byte[] saltBytes = salt.getBytes("UTF-8"); byte[]ivBytes = iv.getBytes("UTF-8");
    // Derive the key
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, iterations, keySize);

    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
    //encrypt the message
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(mode, secret, new IvParameterSpec(ivBytes));
    return cipher;
  }

  public static String AES_encrypt(String plainText, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
    Cipher cipher = generateCipher(Cipher.ENCRYPT_MODE, password, salt, iv, iterations, keySize);
    byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
    Base64.Encoder encoder = Base64.getEncoder();
    return encoder.encodeToString(encryptedTextBytes);
  }

標題

  interface_name: interfaceName  
  strength: 256  
  salt: salt_sixteen1234  
  iterate: 100  
  iv: sixteen_value_12  
  ciphertext: ECtKO7VluxCPFS/D8LVsb2bOQjhViIZm+O3zfMqSwJOLLTpDL4xdgwmIWr+41n5j  

C# 加密

  ...
   using (var csp = new AesCryptoServiceProvider())
   {
          ICryptoTransform e = GetCryptoTransform(csp, true, key, salt, iv);
          byte[] inputBuffer = Encoding.UTF8.GetBytes(plainText);
          byte[] output = e.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
         string encrypted = Convert.ToBase64String(output);

        return encrypted;
   }
  ...

   private static ICryptoTransform GetCryptoTransform(AesCryptoServiceProvider csp, bool encrypting, string password, string salt, string iv, int iterations)
   {
        csp.Mode = CipherMode.CBC;
        csp.Padding = PaddingMode.PKCS7;
        var spec = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(password), Encoding.UTF8.GetBytes(salt), iterations);
        byte[] key = spec.GetBytes(16);

        csp.IV = Encoding.UTF8.GetBytes(iv);
        csp.Key = key;
        if (encrypting)
        {
            return csp.CreateEncryptor();
        }
        return csp.CreateDecryptor();
   }

為了測試任何 C# 加密,我在您的 Java 代碼中添加了一個解密方法並成功運行了一整輪(加密和解密)。

對於 C# 部分,我懶得檢查您的代碼(正如@Topaco 所做的那樣)並使用我自己的代碼和您的憑據來獲取您可以提供給 Java 解密方法的輸出。

讓我們從更長的安全警告開始:代碼使用靜態初始化向量和靜態鹽,並且 PBKDF2 密鑰派生的迭代計數太低(應至少使用 10.000) 這些代碼沒有任何異常處理,僅用於教育目的。

運行 C# 代碼會給出一個簡短的輸出:

AES CBC 256 string encryption with PBKDF2 SHA1 key derivation
plaintext:      The quick brown fox jumps over the lazy dog
ciphertext:     5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4

將密文呈現給 Java 解密將給出以下輸出:

C# AES encrypt to java 8 decrypt
plaintext: The quick brown fox jumps over the lazy dog
ciphertext: 5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4
decryptedtext: The quick brown fox jumps over the lazy dog

decryption of a ciphertext from C#
ciphertextFromCsharp: 5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4
decryptedtextFromCsharp: The quick brown fox jumps over the lazy dog

這兩個代碼都可用於現場自測(Java: https : //repl.it/@javacrypto/JavaAes256EncryptionWithPBKDF2SHA1keyderivation,C#https : //repl.it/@javacrypto/CsharpAes256Pbkdf2Encryption#main.cs )。

C#-代碼:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class Program {
    public static void Main() {
        Console.WriteLine("AES CBC 256 string encryption with PBKDF2 SHA1 key derivation");
        // credentials
    string plaintext = "The quick brown fox jumps over the lazy dog";
        string password = "myPassword";
    string saltString = "salt_sixteen1234";
    var iterationsCount = 100;
    string ivString = "sixteen_value_12";

    Encoding enc = Encoding.UTF8;
        byte[] saltBytes = enc.GetBytes(saltString);
    byte[] iv = enc.GetBytes(ivString);
    byte[] key;

        try {
      // pbkdf2 sha1 key derivation
      using (var pbkdf2 = new Rfc2898DeriveBytes(
            password,
            saltBytes,
            iterationsCount,
            HashAlgorithmName.SHA1))
          {
            key = pbkdf2.GetBytes(32);
          }
            Console.WriteLine("plaintext:      {0}", plaintext);
            string ciphertext = encrypt(key, iv, plaintext);
            Console.WriteLine("ciphertext:     {0}", ciphertext);
        }
        catch(Exception e) {
            Console.WriteLine("Error: {0}", e.Message);
        }
    }

    static string encrypt(byte[] key, byte[] IV, string data) {
        byte[] encrypted;
        using(Aes aesAlg = Aes.Create()) {
            aesAlg.Key = key;
            aesAlg.IV = IV;
            aesAlg.Mode = CipherMode.CBC;
            var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
            // create the streams used for encryption.
            using(var msEncrypt = new MemoryStream()) {
                using(var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
                    using(var swEncrypt = new StreamWriter(csEncrypt)) {
                        //Write all data to the stream.
                        swEncrypt.Write(data);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }
        return Convert.ToBase64String(encrypted);
    }
}

Java代碼:

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 java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println("C# AES encrypt to java 8 decrypt");

        String plaintext = "The quick brown fox jumps over the lazy dog";
        String password = "myPassword";
        String iv = "sixteen_value_12";
        String salt = "salt_sixteen1234";
        int iterations = 100;
        int keySize = 256;
        System.out.println("plaintext: " + plaintext);
        String ciphertext = AES_encrypt(plaintext, password, salt, iv, iterations, keySize);
        System.out.println("ciphertext: " + ciphertext);
        String decryptedtext = AES_decrypt(ciphertext, password, salt, iv, iterations, keySize);
        System.out.println("decryptedtext: " + decryptedtext);
        System.out.println("\ndecryption of a ciphertext from C#");
        String ciphertextFromCsharp = "5HMLSQKEgG+RADgPmf5Eyw0F/GG9sXFuWiHeuZxgpmJP+UoH4MZlvnQDrgnofQy4";
        System.out.println("ciphertextFromCsharp: " + ciphertextFromCsharp);
        String decryptedtextFromCsharp = AES_decrypt(ciphertextFromCsharp, password, salt, iv, iterations, keySize);
        System.out.println("decryptedtextFromCsharp: " + decryptedtextFromCsharp);
   }

    private static Cipher generateCipher(int mode, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
        byte[] saltBytes = salt.getBytes("UTF-8"); byte[]ivBytes = iv.getBytes("UTF-8");
        // Derive the key
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, iterations, keySize);
        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
        //encrypt the message
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(mode, secret, new IvParameterSpec(ivBytes));
        return cipher;
    }

    public static String AES_encrypt(String plainText, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
        Cipher cipher = generateCipher(Cipher.ENCRYPT_MODE, password, salt, iv, iterations, keySize);
        byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
        Base64.Encoder encoder = Base64.getEncoder();
        return encoder.encodeToString(encryptedTextBytes);
    }

    public static String AES_decrypt(String cipherText, String password, String salt, String iv, Integer iterations, Integer keySize) throws Exception {
        Base64.Decoder decoder = Base64.getDecoder();
        Cipher cipher = generateCipher(Cipher.DECRYPT_MODE, password, salt, iv, iterations, keySize);
        return new String(cipher.doFinal(decoder.decode(cipherText)), StandardCharsets.UTF_8);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM