将Java加密代码转换为C#

时间:2014-03-08 15:38:03

标签: c# java encryption cryptography

这是我试图转换为等效C#代码的Java加密代码:

import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.spec.KeySpec;
import java.util.Arrays;

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.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.Validate;

public class Encryptor
{
    private static final String CIPHER_ALOGRITHM = "AES/CBC/PKCS5Padding";
    private static final String KEY_ALOGRITHM = "PBKDF2WithHmacSHA1";
    private static final String KEY_SPEC_ALOGRITHM = "AES";
    private static final String ENCODING = "UTF-8";

    public static String decrypt(String password, String encodedCiphertextAndIv) throws GeneralSecurityException,
        UnsupportedEncodingException
    {
        String[] ra = encodedCiphertextAndIv.split(":");
        byte[] ciphertext = Base64.decodeBase64(ra[0]);
        byte[] iv = Base64.decodeBase64(ra[1]);

        /* Decrypt the message, given derived key and initialization vector. */
        Cipher cipher = Cipher.getInstance(CIPHER_ALOGRITHM);
        cipher.init(Cipher.DECRYPT_MODE, getSecret(password), new IvParameterSpec(iv));
        String plaintext = new String(cipher.doFinal(ciphertext), ENCODING);
        return plaintext;
    }

    static SecretKey getSecret(String password) throws GeneralSecurityException
    {
        byte[] salt = Arrays.copyOf(password.getBytes(), 8);

        /* Derive the key, given password and salt. */
        SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALOGRITHM);
        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1024, 128);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), KEY_SPEC_ALOGRITHM);
        return secret;
    }

    public static String encrypt(String password, String plainText) throws GeneralSecurityException,
        UnsupportedEncodingException
    {
        if (plainText == null)
        {
            return plainText;
        }
        String[] plainTextValues = new String[]
        {
            plainText
        };
        String[] encryptedValues = encrypt(password, plainTextValues);
        return encryptedValues[0];
    }

    public static String[] encrypt(String password, String[] plainTextValues) throws GeneralSecurityException,
        UnsupportedEncodingException
    {
        if (plainTextValues == null || plainTextValues.length == 0)
        {
            return new String[] {};
        }        
        Validate.notEmpty(password, "password must not be empty");

        /* Encrypt the message. */
        Cipher cipher = Cipher.getInstance(CIPHER_ALOGRITHM);
        cipher.init(Cipher.ENCRYPT_MODE, getSecret(password));
        AlgorithmParameters params = cipher.getParameters();
        byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
        String encodedIv = new String(Base64.encodeBase64(iv));

        String[] encryptedValues = new String[plainTextValues.length];
        for (int i = 0; i < plainTextValues.length; i++)
        {
            String plainText = plainTextValues[i];
            if (plainText == null)
            {
                encryptedValues[i] = plainText;
            }
            else
            {
                byte[] ciphertext = cipher.doFinal(plainText.getBytes(ENCODING));
                String encodedCiphertext = new String(Base64.encodeBase64(ciphertext));
                encryptedValues[i] = encodedCiphertext + ":" + encodedIv;
            }
        }
        return encryptedValues;
    }

    public static void main(String[] args) throws Exception
    {
        String password = "The Secret";
        String plainText = "Hello, World!";

        String enc = encrypt(password, plainText);
        System.out.println(enc);
        System.out.println(decrypt(password, enc));
    }
}

这是我尝试过的C#代码:

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

namespace ConsoleApplication1
{
    class Program
    {
        private const string CIPHER_ALOGRITHM = "AES/CBC/PKCS5Padding";
        private const string KEY_ALOGRITHM = "PBKDF2WithHmacSHA1";
        private const string KEY_SPEC_ALOGRITHM = "AES";
        private const string ENCODING = "UTF-8";

        static void Main(string[] args)
        {

            string key = "The Secret";

            string plainTextValue = "Hello, World!";


            Program p = new Program();
            string encryptedvalue = p.Encrypt(key, plainTextValue);
            //Console.WriteLine("encryptedvalaue:{0}", encryptedvalue);

            string decryptedvalue = p.Decrypt(appsecret, encryptedvalue);
            //Console.WriteLine("decryptedvalue:{0}", decryptedvalue);
        }

        public RijndaelManaged GetRijndaelManaged(String secretKey)
        {
            var keyBytes = new byte[16];
            var secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
            Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));
            return new RijndaelManaged 
            { 
                Mode = CipherMode.CBC, 
                Padding = PaddingMode.PKCS7, 
                KeySize = 128, 
                BlockSize = 128, 
                Key = keyBytes, 
                IV = keyBytes 
            };
        }
        public byte[] Encrypt(byte[] plainBytes, RijndaelManaged rijndaelManaged)
        {
            return rijndaelManaged.CreateEncryptor().TransformFinalBlock(plainBytes, 0, plainBytes.Length);
        }

        public byte[] Decrypt(byte[] encryptedData, RijndaelManaged rijndaelManaged)
        {
            return rijndaelManaged.CreateDecryptor().TransformFinalBlock(encryptedData, 0, encryptedData.Length);
        }

        /// <summary>        
        /// Encrypts plaintext using AES 128bit key and a Chain Block Cipher and returns a base64 encoded string        
        /// </summary>        
        /// <param name="plainText">Plain text to encrypt</param>        
        /// <param name="key">Secret key</param>        
        /// <returns>Base64 encoded string</returns>        
        /// 
        public String Encrypt(String key, String plainText)
        {
            var plainBytes = Encoding.UTF8.GetBytes(plainText);
            return Convert.ToBase64String(Encrypt(plainBytes, GetRijndaelManaged(key)));
        }         

        /// <summary>        
        /// Decrypts a base64 encoded string using the given key (AES 128bit key and a Chain Block Cipher)        
        /// </summary>        
        /// <param name="encryptedText">Base64 Encoded String</param>        
        /// <param name="key">Secret Key</param>        
        /// <returns>Decrypted String</returns>     
        /// 
        public String Decrypt(String key, String encryptedText)
        {
            var encryptedBytes = Convert.FromBase64String(encryptedText);
            return Encoding.UTF8.GetString(Decrypt(encryptedBytes, GetRijndaelManaged(key)));
        }
    }
}

但是,使用Java代码解密时,在C#端进行的加密不会产生相同的值。方案是我的Web应用程序(基于.net C#构建)必须将加密数据传输到将解密它的Java应用程序。所以我需要确保.net上的加密等同于Java加密。

需要你的帮助。

1 个答案:

答案 0 :(得分:1)

看起来你没有在C#实现中散列你的密钥。 这一行

 cipher.init(Cipher.ENCRYPT_MODE, getSecret(password));

负责Java代码段中的内容。

但在C#中,您只需将秘密用作纯文本进行加密。

我做了类似的任务,这里是遗漏秘密的缺失部分,允许您为AES加密生成iv和key值:

    var derivedPassword = new Rfc2898DeriveBytes(secretKey, saltBytes);
    var symmetricKey = new RijndaelManaged();
    byte[] keyBytes = derivedPassword.GetBytes(symmetricKey.KeySize/8);
    byte[] initBytes = derivedPassword.GetBytes(symmetricKey.BlockSize/8);