3

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

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

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

我无法控制 Java 端,只有 C# 端。我所有的 C# 解密尝试都给了我垃圾数据,与我的 C# 代码相比,我在 Java 代码中发现的唯一差异是 C# 端缺少 Bouncy Castle。有谁知道我如何将 BouncyCastle 指定为 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;
}
4

3 回答 3

2

正如代码评论:“在 C# 中,您要么直接使用 BC 库,要么不使用。这种“提供者”概念不存在。” 这类似于在 Java 中使用“轻量级 API”。Oracle / OpenJDK 定义的 Java JCE API 没有等效项。

于 2013-11-11T19:03:09.940 回答
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;
    }
于 2013-11-11T21:40:01.510 回答
1

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

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

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

于 2013-11-12T14:12:27.687 回答