2014-04-03 61 views
1

我想弄清楚如何使用ANSI X9.31版本的RSA數字簽名算法創建數字簽名。這與PKCS#1實現不同,主要是由於填充方案。如何在C#中使用ANSI X9.31 RSA創建數字簽名?

我以爲我可以使用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; 
} 

回答

0

棘手。您可以使用或從Bouncy Castle for C#中提取RSA致盲引擎,然後自己執行填充/解除壓縮。在this age old Dr Dobbs article中有描述。

+0

謝謝,我會看看如果我能弄清楚如何做到這一點。 –

+0

如果我使用BouncyCastle,我需要使用「RSABlindingEngine」還是隻使用「RSAEngine」?見上面的例子。 –

+0

任何一個。盲目性是一種避免旁道攻擊的方法,它不會影響結果。通常情況下,您確實想要防範此類攻擊,除非不能進行旁路通道攻擊*和*您的CPU時間不足:) –

相關問題