C#密钥包装/解包PBEWITHSHA256AND256BITAES CBC

时间:2013-11-18 08:22:45

标签: c# java cryptography aes bouncycastle

我在Java中使用 bouncy castle 提供程序进行密钥解包时使用以下代码:

private static byte[] unwrapKey(byte[] toUnwrap, String key) throws Exception {
    byte[] decoded = Base64.decode(toUnwrap);
    if (decoded == null || decoded.length <= 16) {
        throw new RuntimeException("Bad input data.");
    }
    byte[] salt = new byte[16];
    byte[] wrappedKey = new byte[decoded.length - 16];
    System.arraycopy(decoded, 0, salt, 0, 16);
    System.arraycopy(decoded, 16, wrappedKey, 0, decoded.length - 16);
    PBEKeySpec pbeKeySpec = new PBEKeySpec(key.toCharArray());
    SecretKey wrapperKey = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC").generateSecret(pbeKeySpec);
    PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 10);
    Cipher decCipher = Cipher.getInstance("AES/GCM/NoPadding", bcProvider);
    decCipher.init(Cipher.UNWRAP_MODE, wrapperKey, parameterSpec);
    return decCipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY).getEncoded();
}

现在,我需要在C#中做同样的事情。问题是即使有一个BC到C#的端口,我仍然无法使其工作。尝试了不同的事情,并总是得到一些例外。

例如,此代码在最后一行引发“pad block corrupted”异常:

byte[] decoded = Convert.FromBase64String(toUnwrap);
if (decoded == null || decoded.Length <= 16) {
    throw new System.ArgumentException("Bad input data", "toUnwrap");
}
byte[] salt = new byte[16];
byte[] wrappedKey = new byte[decoded.Length - 16];
Array.Copy(decoded, 0, salt, 0, 16);
Array.Copy(decoded, 16, wrappedKey, 0, decoded.Length - 16);
int iterationCount = 10;
String alg = "PBEWithSHA256And256BitAES-CBC-BC";
Asn1Encodable defParams = PbeUtilities.GenerateAlgorithmParameters(alg, salt, iterationCount);
char[] password = key.ToCharArray();
IWrapper wrapper = WrapperUtilities.GetWrapper(alg);
ICipherParameters parameters = PbeUtilities.GenerateCipherParameters(alg, password, defParams);
wrapper.Init(false, parameters);
byte[] pText = wrapper.Unwrap(wrappedKey, 0, wrappedKey.Length);
return pText.ToString();

我怀疑C#默认使用不同类型的填充,但不知道如何在Java代码中强制使用“NoPadding”。

我不确定,如果JAVA代码使用rfc3994是否是这种情况,因为在RFC中你需要提供IV,而这里有一个盐,但没有IV。

我想知道是否有人之前做过,如果有的话,那将是c#analogy。

1 个答案:

答案 0 :(得分:0)

我终于明白了:

public static String unwrapKey(String toUnwrap, String key)
{
    byte[] decoded = Convert.FromBase64String(toUnwrap);
    if (decoded == null || decoded.Length <= 16)
    {
        throw new System.ArgumentException("Bad input data", "toUnwrap");
    }
    byte[] salt = new byte[16];
    byte[] wrappedKey = new byte[decoded.Length - 16];
    Array.Copy(decoded, 0, salt, 0, 16);
    Array.Copy(decoded, 16, wrappedKey, 0, decoded.Length - 16);
    int iterationCount = 10;
    String algSpec = "AES/GCM/NoPadding";
    String algName = "PBEWithSHA256And256BitAES-CBC-BC";

    Asn1Encodable defParams = PbeUtilities.GenerateAlgorithmParameters(algName, salt, iterationCount);
    char[] password = key.ToCharArray();
    IWrapper wrapper = WrapperUtilities.GetWrapper(algSpec);
    ICipherParameters parameters = PbeUtilities.GenerateCipherParameters(algName, password, defParams);
    wrapper.Init(false, parameters);
    byte[] keyText = wrapper.Unwrap(wrappedKey, 0, wrappedKey.Length);
    return Convert.ToBase64String(keyText);
}

这与上面的JAVA代码完全相同。