繁体   English   中英

如何在C#中使用ANSI X9.31 RSA创建数字签名?

[英]How can I create a digital signature using ANSI X9.31 RSA in C#?

我试图弄清楚如何使用RSA数字签名算法的ANSI X9.31版本创建数字签名。 这与PKCS#1的实现不同,主要是由于填充方案。

我以为可以使用RSACryptoServiceProvider来SignHash。 但是,它使用PKCS#1或OAEP。 我不知道如何使用ANS X9.31填充。 救命?

编辑:如果我使用BouncyCastle,是否需要使用“ RSABlindingEngine”,还是可以只使用“ RSAEngine”? 请参见下面的示例:

using System.Security.Cryptography;

public byte[] SignSha256AnsiX931Rsa(
    byte[] data, 
    System.Security.Cryptography.X509Certificates.X509Certificate2 certificate)
{
    // Do a SHA-256 hash of the data, using CNG
    SHA256Cng sha = new SHA256Cng();
    byte[] digest = sha.ComputeHash(data);

    // Pad the hash using ANSI X9.31 padding scheme
    byte[] paddedHash = AnsiX931PadData(digest);

    // Encrypt the data using RSA encryption
    return RsaEncryptData(paddedHash, certificate);
}

/// <summary>
/// Pads the passed in SHA-256 hash (32-bytes) using the padding scheme
/// specified for ANS X9.31 RSA digital signatures.
/// </summary>
/// <param name="sha256HashedData">The 32-byte hash</param>
public byte[] AnsiX931PadData(byte[] sha256HashedData)
{
    // N = Modulus Length (in bytes) = 256, where modulus is 2048-bits (length of private key)
    // M = Message
    // k = Hash Output = Digest = Hash(M)
    // z = Len(k) (in bytes) = 32, where using Hash = SHA-256
    // p = number of fixed padding bytes, in this case 4 (6b, ba, 34, and cc)
    // 
    // Padded Hash = 6b [bb]*x ba [k] 34 cc, where x = 220 (N - z - 4 = 256 - 32 - 4 = 220)
    // [6b bb bb ... bb ba] [Hash(M)] [hashID=34] [cc]
    // 
    // See: 
    // http://www.drdobbs.com/rsa-digital-signatures/184404605?pgno=6
    // http://books.google.com/books?id=7gBn_gEBQesC&lpg=PA388&dq=x9.31%20padding&pg=PA386#v=onepage&q=x9.31%20padding&f=false

    const int MOD_LENGTH = 256; // 2048-bit private key length
    const int PAD_LENGTH = 4; // number of fixed padding bytes, in this case 4 (6b, ba, 34, and cc)
    const int HASH_LENGTH = 32; // where using Hash = SHA-256

    if (sha256HashedData.Length != HASH_LENGTH) throw new ArgumentException("The hash provided is the incorrect length");

    List<byte> paddedHash = new List<byte>(MOD_LENGTH);

    paddedHash.Add(0x6b);

    int bbRepeats = MOD_LENGTH - HASH_LENGTH - PAD_LENGTH;

    for (int ii = 0; ii < bbRepeats; ii++)
    {
        paddedHash.Add(0xbb);
    }

    paddedHash.Add(0xba);
    paddedHash.AddRange(sha256HashedData);
    paddedHash.Add(0x34); // SHA-256 Hash ID; 0x33 = SHA-1
    paddedHash.Add(0xcc);

    return paddedHash.ToArray();
}

/// <summary>
/// Encrypts the data using an X509 certificate and the RSA encryption scheme 
/// </summary>
public byte[] RsaEncryptData(
    byte[] data, 
    System.Security.Cryptography.X509Certificates.X509Certificate2 certificate)
{
    Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine engine = new Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine();
    engine.Init(true, getBouncyPrivateKey(certificate));
    return engine.ProcessBlock(data, 0, data.Length);
}

/// <summary>
/// Gets the private key from an X509Certificate
/// </summary>
private Org.BouncyCastle.Crypto.AsymmetricKeyParameter getBouncyPrivateKey(
    System.Security.Cryptography.X509Certificates.X509Certificate2 certificate)
{
    // Need to transform the key from X509 to RSACrypto so we can do SHA-256 since
    // X509 only supports SHA-1:
    System.Security.Cryptography.RSACryptoServiceProvider key = new System.Security.Cryptography.RSACryptoServiceProvider(2048);

    // Round-trip the key to XML and back, there might be a better way but this works
    key.FromXmlString(certificate.PrivateKey.ToXmlString(true));

    return Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(key).Private;
}

棘手。 您可以使用或从Bouncy Castle中提取RSA盲引擎用于C# ,然后自己执行填充/取消填充。 Dobbs博士这本古老的文章对此进行了描述。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM