如何在C#中添加BouncyCastleProvider?

时间:2013-11-11 17:26:47

标签: c# java encryption bouncycastle

我有一个Java加密例程,我需要用C#解密。 Java例程正在使用我无法在C#中复制的Bouncy Castle系列:

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

这是Java代码中对Bouncy Castle的唯一引用。

我无法控制Java端,只能控制C#端。我的所有C#解密尝试都给了我垃圾数据,与我的C#代码相比,我在Java代码中发现的唯一差异是C#端缺少Bouncy Castle。有谁知道如何将CouncyCastle指定为C#中的安全提供程序?我在他们的网站上浏览了Bouncy Castle的源代码,但没有运气。


编辑:鉴于到目前为止的回复,我已更新我的代码以使用Bouncy Castle。我在下面添加了我的C#解密代码和Java加密代码。当我使用Bouncy Castle时,我仍然无法使解密正常工作。我必须忽略一些简单的东西,但我看不到它......任何想法都会受到赞赏。

C#解密代码:

    public string Decrypt(string stringToDecrypt, string encryption_Key, string init_Vector, string salt)
{
    byte[] SALT = Convert.FromBase64String(salt);
    int iterations = 12345;
    var rfc2898 = new System.Security.Cryptography.Rfc2898DeriveBytes(encryption_Key, SALT, iterations);
    byte[] KEY = rfc2898.GetBytes(16);
    KeyParameter aesKeyParam = ParameterUtilities.CreateKeyParameter("AES", KEY);
    byte[] IV = Encoding.UTF8.GetBytes(init_Vector);
    ParametersWithIV aesIVKeyParam = new ParametersWithIV(aesKeyParam, IV);

    IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CBC/PKCS5Padding");
    cipher.Init(false, aesIVKeyParam);

    //byte[] bytesToDecrypt = Convert.FromBase64String(stringToDecrypt);
        // Gives me "pad block corrupted" error
    //byte[] bytesToDecrypt = Encoding.UTF8.GetBytes(stringToDecrypt);
        // Gives me "last block incomplete in decryption" error
    byte[] bytesToDecrypt = Base64.Decode(Encoding.UTF8.GetBytes(stringToDecrypt));
        // Gives me "pad block corrupted" error
    byte[] output = cipher.DoFinal(bytesToDecrypt);

    return Convert.ToBase64String(output);
}

Java代码:

public class testaes {
/**
 * The iteration count for key generation algorithm.
 */
private static final int KEY_ITERATION_COUNT = 12345;

/**
 * The key length in bits.
 */
private static final int KEY_LENGTH = 128;

/**
 * The algorithm for cipher initialization.
 */
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";

/**
 * The algorithm for key factory selection.
 */
private static final String KEY_FACTORY_ALGORITHM = "PBKDF2WithHmacSHA1";

/**
 * The algorithm for key generation.
 */
private static final String KEY_ALGORITHM = "AES";

/**
 * The byte encoding.
 */
private static final String BYTE_ENCODING = "UTF-8";

private static testaes instance = null;


public testaes() {
    super();
}

public static testaes getInstance() {
    if (instance == null) {
        instance = new testaes();
    }
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    return instance;
}

/**
 * Instantiates the cipher.
 */
private Cipher initCipher(int opmode) throws Exception, NoSuchAlgorithmException, InvalidKeySpecException,
        NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, UnsupportedEncodingException {
    String access = "XXXXX";

    byte[] salt = "XXXXX".getBytes();

    String ivString = "XXXXX";


    // Build the key from password and salt.
    char[] accessCharArray = access.toCharArray();
    byte[] saltByteArray = Base64.decodeBase64(salt);
    SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
    KeySpec spec = new PBEKeySpec(accessCharArray, saltByteArray, KEY_ITERATION_COUNT, KEY_LENGTH);
    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secretKey = new SecretKeySpec(tmp.getEncoded(), KEY_ALGORITHM);

    // Create a cipher based on AES transformation.
    Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
    // Initialize cipher to with Secret Key and IV.
    cipher.init(opmode, secretKey, new IvParameterSpec(ivString.getBytes(BYTE_ENCODING)));
    return cipher;
}

/**
 * Encrypts the data.
 * 
 * @param originalString
 *            The data to be encrypted.
 * @return The encrypted data as String.
 */
public String encryptAES(String originalString) {
    String encryptedString = null;
    try {
        Cipher cipher = initCipher(Cipher.ENCRYPT_MODE);
        byte[] encryptedBytes = cipher.doFinal(originalString.getBytes());
        String base64Encoded = new String(Base64.encodeBase64(encryptedBytes), Charset.forName(BYTE_ENCODING));
        String urlEncoded = URLEncoder.encode(base64Encoded, BYTE_ENCODING);
        encryptedString = urlEncoded;
    }  catch (Exception e) {
        e.printStackTrace();
    }
    return encryptedString;
}

/**
 * Decrypts the data.
 * 
 * @param encryptedString
 *            The encrypted data that is to be decrypted.
 * @return The decrypted (original) data as string.
 */
public String decryptAES(String encryptedString) {
    String decryptedString = null;

    try {
        Cipher cipher = initCipher(Cipher.DECRYPT_MODE);
        String urlDecoded = URLDecoder.decode(encryptedString, BYTE_ENCODING);
        byte[] encryptedBytes = Base64.decodeBase64(urlDecoded.getBytes(Charset.forName(BYTE_ENCODING)));
        byte[] originalBytes = cipher.doFinal(encryptedBytes);
        decryptedString = new String(originalBytes);
    }  catch (Exception e) {
        e.printStackTrace();
    }
    return decryptedString;
}

3 个答案:

答案 0 :(得分:2)

代码注释:“在C#中,您可以直接使用BC库,也可以不使用。这种”提供者“概念不存在。”这类似于在Java中使用“轻量级API”。 Oracle / OpenJDK定义的Java JCE API没有等价物。

答案 1 :(得分:2)

我以前必须做类似的事情。我的应用程序必须使用C#加密数据,然后用Java解密。但是,我写了一些在C#侧解密数据的东西。这是我的代码:

public static byte[] Decrypt3(byte[] data, string pemFilename)
{
    try {
        AsymmetricKeyParameter key = readPrivateKey(pemFilename);

        RsaEngine e = new RsaEngine();

        e.Init(false, key);

        byte[] cipheredBytes = e.ProcessBlock(data, 0, data.Length);
        return cipheredBytes;

    } catch (Exception e) {
        Debug.Log ("Exception in Decrypt3: " + e.Message);
        return GetBytes(e.Message);
    }
}

修改

添加我使用过的库:

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using UnityEngine;

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Engines;

**编辑2:** 添加readPrivateKey函数:

static AsymmetricKeyParameter readPrivateKey(string privateKeyFileName)
{
    AsymmetricCipherKeyPair keyPair;

    using (var reader = File.OpenText(privateKeyFileName))
        keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();

    return keyPair.Private;
}

我也就此问题提出了几个问题,如果你看一下我通过个人资料或搜索网站提出的问题,你也可以找到一些帮助。

**编辑3:** //添加加密功能

public static byte[] Encrypt3(byte[] data, string pemFilename)
    {
        byte[] cipheredBytes = null;
        try {
            AsymmetricKeyParameter key = ReadAsymmetricKeyParameter(pemFilename);

            RsaEngine e = new RsaEngine();

            e.Init(true, key);

            //Debug.Log ("Encryption msg: " + inputMessage);
            //cipheredBytes = GetBytes(inputMessage);
            //Debug.Log ("bytes: " + GetString(cipheredBytes));
            cipheredBytes = e.ProcessBlock(data, 0, data.Length);
        }
        catch (Exception e) {
            Debug.Log (e.Message);  
        }
        return cipheredBytes;
    }

答案 2 :(得分:1)

在加密一切需要完全匹配双方。这意味着检查所有内容是否匹配,逐字节。你的IV匹配字节是否为字节?您的最终密钥(在KDF之后)是否与字节匹配?这两个cyphertexts是否匹配byte的字节?两个系统之间可能存在传输问题。

尝试解密时是否收到任何错误消息,例如“Bad Padding”错误?如果不这样做,则填充正在被正确解密,即使大部分消息没有。这可能表明问题不在于解密本身,而在系统的其他地方。

您是否尝试过传递一条非常简单的消息,“Hello World!”通过这个过程?那怎么办?