Вопрос

I'm trying to figure out how to create a digital signature using the ANSI X9.31 version of the RSA digital signature algorithm. This differs from the PKCS#1 implementation, mainly due to the padding scheme.

I thought I could use the RSACryptoServiceProvider to SignHash; however, this uses either PKCS#1 or OAEP. I can't figure out how to use the ANS X9.31 padding. Help?

EDIT: If I use BouncyCastle, do I need to use the "RSABlindingEngine" or can I just use the "RSAEngine"? See example below:

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;
}
Это было полезно?

Решение

Tricky. You could use or extract the RSA blinding engine from Bouncy Castle for C# and then perform the padding / unpadding yourself. It's described in this age old Dr Dobbs article.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top