/// <summary> /// Verifies the data given as parameter with the given public key. /// </summary> /// <remarks> /// <para>The function calculates a message digest over the given signature /// data and verifies the digest with the digest stored in the /// signature packet.</para> /// <para>The results of the verify operation are directly stored /// in the SignatureStatus property of this class.</para> /// </remarks> /// <param name="bSignedData">The data that is to be verified.</param> /// <param name="pkpKey">The key that is to verify the signature</param> public void Verify(byte[] bSignedData, PublicKeyPacket pkpKey) { System.Security.Cryptography.HashAlgorithm haVerifyer; AsymmetricCipher acVerifyer; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: haVerifyer = System.Security.Cryptography.MD5.Create(); break; case HashAlgorithms.SHA1: haVerifyer = System.Security.Cryptography.SHA1.Create(); break; default: throw(new System.Exception("Currently only MD5 and SHA1 are implemented as hash algorithms!")); } switch (this.SignatureAlgorithm) { case AsymAlgorithms.DSA: acVerifyer = new SharpPrivacy.SharpPrivacyLib.Cipher.DSA(); break; case AsymAlgorithms.RSA_Encrypt_Sign: case AsymAlgorithms.RSA_Sign_Only: acVerifyer = new SharpPrivacy.SharpPrivacyLib.Cipher.RSA(); break; default: throw(new System.Exception("Currently only DSA and RSA are implemented as signature algorithms!")); } byte[] bSignature = new byte[0]; int iCounter = 0; if (this.Version <= SignaturePacketVersionNumbers.v3) { bSignature = new byte[5]; bSignature[iCounter++] = (byte)this.SignatureType; long lTime = (dtTimeCreated.Ticks - new DateTime(1970, 1, 1).Ticks)/10000000; bSignature[iCounter++] = (byte)((lTime >> 24) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 16) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lTime & 0xFF); } else { //Hashed Subpackets Length int lHashedSubPacketLength = 0; for (int i=0; i<this.HashedSubPackets.Length; i++) { lHashedSubPacketLength += this.HashedSubPackets[i].Generate().Length; } bSignature = new byte[lHashedSubPacketLength + 12]; bSignature[iCounter++] = 4; // Version bSignature[iCounter++] = (byte)this.SignatureType; bSignature[iCounter++] = (byte)this.SignatureAlgorithm; bSignature[iCounter++] = (byte)this.HashAlgorithm; //Hashed Subpackets bSignature[iCounter++] = (byte)((lHashedSubPacketLength >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lHashedSubPacketLength & 0xFF); for (int i=0; i<this.HashedSubPackets.Length; i++) { byte[] bSubPacket = this.HashedSubPackets[i].Generate(); Array.Copy(bSubPacket, 0, bSignature, iCounter, bSubPacket.Length); iCounter += bSubPacket.Length; } //Final Trailer of 6 bytes bSignature[iCounter++] = 0x04; bSignature[iCounter++] = 0xFF; bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 24) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 16) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 8) & 0xFF); bSignature[iCounter++] = (byte)((lHashedSubPacketLength+6) & 0xFF); } byte[] bData = new byte[bSignedData.Length + bSignature.Length]; Array.Copy(bSignedData, bData, bSignedData.Length); Array.Copy(bSignature, 0, bData, bSignedData.Length, bSignature.Length); byte[] bHash = haVerifyer.ComputeHash(bData); BigInteger biHash = new BigInteger(bHash); //PKCS1 Encode the hash if (this.SignatureAlgorithm != AsymAlgorithms.DSA) { // We encode the MD in this way: // 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) // PAD consists of FF bytes. byte[] bASN = new byte[0]; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: bASN = new byte[] {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}; break; case HashAlgorithms.SHA1: bASN = new byte[] {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14}; break; } int iFrameSize = (pkpKey.KeyMaterial[0].bitCount() + 7) / 8; byte[] bFrame = new byte[iFrameSize]; int iASNCounter = 0; bFrame[iASNCounter++] = 0; bFrame[iASNCounter++] = 1; int iFFLength = iFrameSize - bHash.Length - bASN.Length - 3; for (int i=0; i<iFFLength; i++) { bFrame[iASNCounter++] = 0xFF; } bFrame[iASNCounter++] = 0; Array.Copy(bASN, 0, bFrame, iASNCounter, bASN.Length); iASNCounter += bASN.Length; Array.Copy(bHash, 0, bFrame, iASNCounter, bHash.Length); biHash = new BigInteger(bFrame); } if (acVerifyer.Verify(this.Signature, biHash, pkpKey)) { ssSignatureStatus = SignatureStatusTypes.Valid; } else { ssSignatureStatus = SignatureStatusTypes.Invalid; } }
private BigInteger[][] GenerateRSAEncryptionKey(int iKeySize) { RSA rsaKeyGenerator = new RSA(); BigInteger[][] biEncryptionKey = rsaKeyGenerator.Generate(iKeySize); return biEncryptionKey; }
/// <summary> /// Signes the data given as parameter with the given secret key. /// The given password has to fit the given key. /// </summary> /// <remarks> /// <para>The function calculates a message digest over the given signature /// data and signes the digest with the given key.</para> /// <para>The results of the signature operation are directly stored /// in the Signature property of this class.</para> /// </remarks> /// <param name="bSignedData">The data that is to be signed.</param> /// <param name="skpKey">The key that is to sign the data</param> /// <param name="strPassphrase">The passphrase that is neccessary to /// decrypt the given key.</param> public void Sign(byte[] bSignedData, SecretKeyPacket skpKey, string strPassphrase) { System.Security.Cryptography.HashAlgorithm haSigner; AsymmetricCipher acSigner; this.SignatureAlgorithm = skpKey.PublicKey.Algorithm; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: haSigner = System.Security.Cryptography.MD5.Create(); break; case HashAlgorithms.SHA1: haSigner = System.Security.Cryptography.SHA1.Create(); break; default: throw(new System.Exception("Currently only MD5 and SHA1 are implemented as hash algorithms!")); } switch (this.SignatureAlgorithm) { case AsymAlgorithms.DSA: acSigner = new SharpPrivacy.SharpPrivacyLib.Cipher.DSA(); break; case AsymAlgorithms.RSA_Encrypt_Sign: case AsymAlgorithms.RSA_Sign_Only: acSigner = new SharpPrivacy.SharpPrivacyLib.Cipher.RSA(); break; default: throw(new System.Exception("Currently only DSA and RSA are implemented as signature algorithms!")); } byte[] bSignature = new byte[0]; int iCounter = 0; if (this.Version <= SignaturePacketVersionNumbers.v3) { bSignature = new byte[5]; bSignature[iCounter++] = (byte)this.SignatureType; long lTime = (dtTimeCreated.Ticks - new DateTime(1970, 1, 1).Ticks)/10000000; bSignature[iCounter++] = (byte)((lTime >> 24) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 16) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lTime & 0xFF); } else { // Add Issuer KeyID Subpacket if it's not there. try { ulong lTestForKeyID = this.KeyID; } catch (Exception) { SignatureSubPacket sspIssuerKeyID = new SignatureSubPacket(); sspIssuerKeyID.Type = SignatureSubPacketTypes.IssuerKeyID; sspIssuerKeyID.KeyID = this.lKeyID; this.AddSubPacket(sspIssuerKeyID, true); } // Add TimeCreated Subpacket if it's not there. try { this.FindSignatureCreationTime(); } catch (Exception) { SignatureSubPacket sspCreationTime = new SignatureSubPacket(); sspCreationTime.Type = SignatureSubPacketTypes.SignatureCreationTime; sspCreationTime.TimeCreated = DateTime.Now; this.AddSubPacket(sspCreationTime, true); } //Hashed Subpackets Length int lHashedSubPacketLength = 0; for (int i=0; i<this.HashedSubPackets.Length; i++) { lHashedSubPacketLength += this.HashedSubPackets[i].Generate().Length; } bSignature = new byte[lHashedSubPacketLength + 12]; bSignature[iCounter++] = 4; // Version bSignature[iCounter++] = (byte)this.SignatureType; bSignature[iCounter++] = (byte)this.SignatureAlgorithm; bSignature[iCounter++] = (byte)this.HashAlgorithm; //Hashed bSignature[iCounter++] = (byte)((lHashedSubPacketLength >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lHashedSubPacketLength & 0xFF); for (int i=0; i<this.HashedSubPackets.Length; i++) { byte[] bSubPacket = this.HashedSubPackets[i].Generate(); Array.Copy(bSubPacket, 0, bSignature, iCounter, bSubPacket.Length); iCounter += bSubPacket.Length; } //Final Trailer of 6 bytes bSignature[iCounter++] = 0x04; bSignature[iCounter++] = 0xFF; bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 24) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 16) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength+6) >> 8) & 0xFF); bSignature[iCounter++] = (byte)((lHashedSubPacketLength+6) & 0xFF); } byte[] bData = new byte[bSignedData.Length + bSignature.Length]; Array.Copy(bSignedData, bData, bSignedData.Length); Array.Copy(bSignature, 0, bData, bSignedData.Length, bSignature.Length); byte[] bHash = haSigner.ComputeHash(bData); BigInteger biHash = new BigInteger(bHash); //PKCS1 Encode the hash if (this.SignatureAlgorithm != AsymAlgorithms.DSA) { // We encode the MD in this way: // 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) // PAD consists of FF bytes. byte[] bASN = new byte[0]; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: bASN = new byte[] {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}; break; case HashAlgorithms.SHA1: bASN = new byte[] {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14}; break; } int iFrameSize = (skpKey.PublicKey.KeyMaterial[0].bitCount() + 7) / 8; byte[] bFrame = new byte[iFrameSize]; int iASNCounter = 0; bFrame[iASNCounter++] = 0; bFrame[iASNCounter++] = 1; int iFFLength = iFrameSize - bHash.Length - bASN.Length - 3; for (int i=0; i<iFFLength; i++) bFrame[iASNCounter++] = 0xFF; bFrame[iASNCounter++] = 0; Array.Copy(bASN, 0, bFrame, iASNCounter, bASN.Length); iASNCounter += bASN.Length; Array.Copy(bHash, 0, bFrame, iASNCounter, bHash.Length); biHash = new BigInteger(bFrame); } sSignedHash16Bit = (ushort)((bHash[0] << 8) + bHash[1]); biSignature = acSigner.Sign(biHash, skpKey, strPassphrase); this.bIsUpdated = true; }
/// <summary> /// Encryptes the session key stored in the SessionKey property /// and saves the results in the EncryptedSessionKey property. /// </summary> /// <remarks>This method also calles EncodeSessionKey so that it /// does not have been called before calling EncryptSessionKey. /// <p></p> /// Please note: calling this function takes some time, because /// asymmetrical encryption takes some time! /// </remarks> /// <param name="pkpPacket">An PublicKeyPacket to which /// the sessionkey should be encrypted to.</param> public void EncryptSessionKey(PublicKeyPacket pkpPacket) { EncodeSessionKey(pkpPacket.KeyMaterial[0].bitCount()); AsymmetricCipher acCipher = new RSA(); switch (aaPublicAlgorithm) { case AsymAlgorithms.ElGama_Encrypt_Sign: case AsymAlgorithms.ElGamal_Encrypt_Only: acCipher = new ElGamal(); break; case AsymAlgorithms.RSA_Encrypt_Only: case AsymAlgorithms.RSA_Encrypt_Sign: acCipher = new RSA(); break; default: throw new System.Exception("The chosen public key algorithm is not yet implemented!"); } this.bIsUpdated = true; biEncryptedSessionKey = acCipher.Encrypt(new BigInteger(this.bEncodedSessionKey), pkpPacket); }
/// <summary> /// Decrypts the session key stored in the EncryptedSessionKey /// property and saves the decrypted key in the EncodedSessionKey /// property. /// </summary> /// <remarks>This function also calls DecodeSessionKey so that the /// decrypted and decoded sessionkey is stored in the /// SessionKey property.</remarks> /// <param name="tskKey">A transportable secret key that is used to /// decrypt the encrypted session key.</param> /// <param name="strPassphrase">The passphrase used to decrypt the /// encrypted key material of the given transportable secret /// key.</param> public void DecryptSessionKey(TransportableSecretKey tskKey, string strPassphrase) { AsymmetricCipher acCipher = new RSA(); switch (aaPublicAlgorithm) { case AsymAlgorithms.ElGama_Encrypt_Sign: case AsymAlgorithms.ElGamal_Encrypt_Only: acCipher = new ElGamal(); break; case AsymAlgorithms.RSA_Encrypt_Only: case AsymAlgorithms.RSA_Encrypt_Sign: acCipher = new RSA(); break; default: throw new System.Exception("The chosen public key algorithm is not yet implemented!"); } bool bFound = false; SecretKeyPacket skpKey = new SecretKeyPacket(); IEnumerator ieSubkeys = tskKey.SubKeys.GetEnumerator(); while (ieSubkeys.MoveNext()) { if (!(ieSubkeys.Current is SecretKeyPacket)) throw new System.Exception("Expected a secret key packet, but did not find one!"); skpKey = (SecretKeyPacket)ieSubkeys.Current; if (skpKey.PublicKey.KeyID == lKeyID) { bFound = true; continue; } } // check if the message was encrypted with the primary key if (!bFound) { if (tskKey.PrimaryKey.PublicKey.KeyID == lKeyID) { skpKey = tskKey.PrimaryKey; } else { //theoretically we should never see this exception, as //encrytped message makes sure we only get fitting secret //keys, but just in case someone calls this directly, we //throw an exception throw new System.Exception("No fitting secret key found!"); } } BigInteger biKey = acCipher.Decrypt(this.biEncryptedSessionKey, skpKey, strPassphrase); this.bEncodedSessionKey = biKey.getBytes(); DecodeSessionKey(); }
/// <summary> /// Verifies the data given as parameter with the given public key. /// </summary> /// <remarks> /// <para>The function calculates a message digest over the given signature /// data and verifies the digest with the digest stored in the /// signature packet.</para> /// <para>The results of the verify operation are directly stored /// in the SignatureStatus property of this class.</para> /// </remarks> /// <param name="bSignedData">The data that is to be verified.</param> /// <param name="pkpKey">The key that is to verify the signature</param> public void Verify(byte[] bSignedData, PublicKeyPacket pkpKey) { System.Security.Cryptography.HashAlgorithm haVerifyer; AsymmetricCipher acVerifyer; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: haVerifyer = System.Security.Cryptography.MD5.Create(); break; case HashAlgorithms.SHA1: haVerifyer = System.Security.Cryptography.SHA1.Create(); break; default: throw(new System.Exception("Currently only MD5 and SHA1 are implemented as hash algorithms!")); } switch (this.SignatureAlgorithm) { case AsymAlgorithms.DSA: acVerifyer = new SharpPrivacy.SharpPrivacyLib.Cipher.DSA(); break; case AsymAlgorithms.RSA_Encrypt_Sign: case AsymAlgorithms.RSA_Sign_Only: acVerifyer = new SharpPrivacy.SharpPrivacyLib.Cipher.RSA(); break; default: throw(new System.Exception("Currently only DSA and RSA are implemented as signature algorithms!")); } byte[] bSignature = new byte[0]; int iCounter = 0; if (this.Version <= SignaturePacketVersionNumbers.v3) { bSignature = new byte[5]; bSignature[iCounter++] = (byte)this.SignatureType; long lTime = (dtTimeCreated.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000; bSignature[iCounter++] = (byte)((lTime >> 24) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 16) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lTime & 0xFF); } else { //Hashed Subpackets Length int lHashedSubPacketLength = 0; for (int i = 0; i < this.HashedSubPackets.Length; i++) { lHashedSubPacketLength += this.HashedSubPackets[i].Generate().Length; } bSignature = new byte[lHashedSubPacketLength + 12]; bSignature[iCounter++] = 4; // Version bSignature[iCounter++] = (byte)this.SignatureType; bSignature[iCounter++] = (byte)this.SignatureAlgorithm; bSignature[iCounter++] = (byte)this.HashAlgorithm; //Hashed Subpackets bSignature[iCounter++] = (byte)((lHashedSubPacketLength >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lHashedSubPacketLength & 0xFF); for (int i = 0; i < this.HashedSubPackets.Length; i++) { byte[] bSubPacket = this.HashedSubPackets[i].Generate(); Array.Copy(bSubPacket, 0, bSignature, iCounter, bSubPacket.Length); iCounter += bSubPacket.Length; } //Final Trailer of 6 bytes bSignature[iCounter++] = 0x04; bSignature[iCounter++] = 0xFF; bSignature[iCounter++] = (byte)(((lHashedSubPacketLength + 6) >> 24) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength + 6) >> 16) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength + 6) >> 8) & 0xFF); bSignature[iCounter++] = (byte)((lHashedSubPacketLength + 6) & 0xFF); } byte[] bData = new byte[bSignedData.Length + bSignature.Length]; Array.Copy(bSignedData, bData, bSignedData.Length); Array.Copy(bSignature, 0, bData, bSignedData.Length, bSignature.Length); byte[] bHash = haVerifyer.ComputeHash(bData); BigInteger biHash = new BigInteger(bHash); //PKCS1 Encode the hash if (this.SignatureAlgorithm != AsymAlgorithms.DSA) { // We encode the MD in this way: // 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) // PAD consists of FF bytes. byte[] bASN = new byte[0]; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: bASN = new byte[] { 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; break; case HashAlgorithms.SHA1: bASN = new byte[] { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 }; break; } int iFrameSize = (pkpKey.KeyMaterial[0].bitCount() + 7) / 8; byte[] bFrame = new byte[iFrameSize]; int iASNCounter = 0; bFrame[iASNCounter++] = 0; bFrame[iASNCounter++] = 1; int iFFLength = iFrameSize - bHash.Length - bASN.Length - 3; for (int i = 0; i < iFFLength; i++) { bFrame[iASNCounter++] = 0xFF; } bFrame[iASNCounter++] = 0; Array.Copy(bASN, 0, bFrame, iASNCounter, bASN.Length); iASNCounter += bASN.Length; Array.Copy(bHash, 0, bFrame, iASNCounter, bHash.Length); biHash = new BigInteger(bFrame); } if (acVerifyer.Verify(this.Signature, biHash, pkpKey)) { ssSignatureStatus = SignatureStatusTypes.Valid; } else { ssSignatureStatus = SignatureStatusTypes.Invalid; } }
/// <summary> /// Signes the data given as parameter with the given secret key. /// The given password has to fit the given key. /// </summary> /// <remarks> /// <para>The function calculates a message digest over the given signature /// data and signes the digest with the given key.</para> /// <para>The results of the signature operation are directly stored /// in the Signature property of this class.</para> /// </remarks> /// <param name="bSignedData">The data that is to be signed.</param> /// <param name="skpKey">The key that is to sign the data</param> /// <param name="strPassphrase">The passphrase that is neccessary to /// decrypt the given key.</param> public void Sign(byte[] bSignedData, SecretKeyPacket skpKey, string strPassphrase) { System.Security.Cryptography.HashAlgorithm haSigner; AsymmetricCipher acSigner; this.SignatureAlgorithm = skpKey.PublicKey.Algorithm; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: haSigner = System.Security.Cryptography.MD5.Create(); break; case HashAlgorithms.SHA1: haSigner = System.Security.Cryptography.SHA1.Create(); break; default: throw(new System.Exception("Currently only MD5 and SHA1 are implemented as hash algorithms!")); } switch (this.SignatureAlgorithm) { case AsymAlgorithms.DSA: acSigner = new SharpPrivacy.SharpPrivacyLib.Cipher.DSA(); break; case AsymAlgorithms.RSA_Encrypt_Sign: case AsymAlgorithms.RSA_Sign_Only: acSigner = new SharpPrivacy.SharpPrivacyLib.Cipher.RSA(); break; default: throw(new System.Exception("Currently only DSA and RSA are implemented as signature algorithms!")); } byte[] bSignature = new byte[0]; int iCounter = 0; if (this.Version <= SignaturePacketVersionNumbers.v3) { bSignature = new byte[5]; bSignature[iCounter++] = (byte)this.SignatureType; long lTime = (dtTimeCreated.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000; bSignature[iCounter++] = (byte)((lTime >> 24) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 16) & 0xFF); bSignature[iCounter++] = (byte)((lTime >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lTime & 0xFF); } else { // Add Issuer KeyID Subpacket if it's not there. try { ulong lTestForKeyID = this.KeyID; } catch (Exception) { SignatureSubPacket sspIssuerKeyID = new SignatureSubPacket(); sspIssuerKeyID.Type = SignatureSubPacketTypes.IssuerKeyID; sspIssuerKeyID.KeyID = this.lKeyID; this.AddSubPacket(sspIssuerKeyID, true); } // Add TimeCreated Subpacket if it's not there. try { this.FindSignatureCreationTime(); } catch (Exception) { SignatureSubPacket sspCreationTime = new SignatureSubPacket(); sspCreationTime.Type = SignatureSubPacketTypes.SignatureCreationTime; sspCreationTime.TimeCreated = DateTime.Now; this.AddSubPacket(sspCreationTime, true); } //Hashed Subpackets Length int lHashedSubPacketLength = 0; for (int i = 0; i < this.HashedSubPackets.Length; i++) { lHashedSubPacketLength += this.HashedSubPackets[i].Generate().Length; } bSignature = new byte[lHashedSubPacketLength + 12]; bSignature[iCounter++] = 4; // Version bSignature[iCounter++] = (byte)this.SignatureType; bSignature[iCounter++] = (byte)this.SignatureAlgorithm; bSignature[iCounter++] = (byte)this.HashAlgorithm; //Hashed bSignature[iCounter++] = (byte)((lHashedSubPacketLength >> 8) & 0xFF); bSignature[iCounter++] = (byte)(lHashedSubPacketLength & 0xFF); for (int i = 0; i < this.HashedSubPackets.Length; i++) { byte[] bSubPacket = this.HashedSubPackets[i].Generate(); Array.Copy(bSubPacket, 0, bSignature, iCounter, bSubPacket.Length); iCounter += bSubPacket.Length; } //Final Trailer of 6 bytes bSignature[iCounter++] = 0x04; bSignature[iCounter++] = 0xFF; bSignature[iCounter++] = (byte)(((lHashedSubPacketLength + 6) >> 24) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength + 6) >> 16) & 0xFF); bSignature[iCounter++] = (byte)(((lHashedSubPacketLength + 6) >> 8) & 0xFF); bSignature[iCounter++] = (byte)((lHashedSubPacketLength + 6) & 0xFF); } byte[] bData = new byte[bSignedData.Length + bSignature.Length]; Array.Copy(bSignedData, bData, bSignedData.Length); Array.Copy(bSignature, 0, bData, bSignedData.Length, bSignature.Length); byte[] bHash = haSigner.ComputeHash(bData); BigInteger biHash = new BigInteger(bHash); //PKCS1 Encode the hash if (this.SignatureAlgorithm != AsymAlgorithms.DSA) { // We encode the MD in this way: // 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) // PAD consists of FF bytes. byte[] bASN = new byte[0]; switch (this.HashAlgorithm) { case HashAlgorithms.MD5: bASN = new byte[] { 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; break; case HashAlgorithms.SHA1: bASN = new byte[] { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 }; break; } int iFrameSize = (skpKey.PublicKey.KeyMaterial[0].bitCount() + 7) / 8; byte[] bFrame = new byte[iFrameSize]; int iASNCounter = 0; bFrame[iASNCounter++] = 0; bFrame[iASNCounter++] = 1; int iFFLength = iFrameSize - bHash.Length - bASN.Length - 3; for (int i = 0; i < iFFLength; i++) { bFrame[iASNCounter++] = 0xFF; } bFrame[iASNCounter++] = 0; Array.Copy(bASN, 0, bFrame, iASNCounter, bASN.Length); iASNCounter += bASN.Length; Array.Copy(bHash, 0, bFrame, iASNCounter, bHash.Length); biHash = new BigInteger(bFrame); } sSignedHash16Bit = (ushort)((bHash[0] << 8) + bHash[1]); biSignature = acSigner.Sign(biHash, skpKey, strPassphrase); this.bIsUpdated = true; }