/// <summary> /// Generates the transportable secret key out of the properties /// in this. /// </summary> /// <returns>Returns a byte array containing the openpgp encoded /// representation of the transportable secret key.</returns> /// <remarks> /// Generates the transportable secret key out of the properties /// in this. /// </remarks> public byte[] Generate() { if (alUserIDs.Count == 0) { throw new Exception("A transportable secret key must have at least one userid assigned to the primary key!"); } byte[] bSecretKey = skpPrimaryKey.Generate(); byte[] bUserIDs = new byte[0]; byte[] bSubkeys = new byte[0]; IEnumerator ieUserIDs = alUserIDs.GetEnumerator(); while (ieUserIDs.MoveNext()) { if (!(ieUserIDs.Current is UserIDPacket)) { continue; } UserIDPacket uipID = (UserIDPacket)ieUserIDs.Current; byte[] bUserID = uipID.Generate(); byte[] bOldUserIDs = new byte[bUserIDs.Length]; bUserIDs.CopyTo(bOldUserIDs, 0); bUserIDs = new byte[bOldUserIDs.Length + bUserID.Length]; bOldUserIDs.CopyTo(bUserIDs, 0); bUserID.CopyTo(bUserIDs, bOldUserIDs.Length); } IEnumerator ieSubkeys = alSubkeys.GetEnumerator(); while (ieSubkeys.MoveNext()) { if (!(ieSubkeys.Current is SecretKeyPacket)) { continue; } SecretKeyPacket skpSubkey = (SecretKeyPacket)ieSubkeys.Current; byte[] bSubkey = skpSubkey.Generate(); byte[] bOldSubkeys = new byte[bSubkeys.Length]; bSubkeys.CopyTo(bOldSubkeys, 0); bSubkeys = new byte[bOldSubkeys.Length + bSubkey.Length]; bOldSubkeys.CopyTo(bSubkeys, 0); bSubkey.CopyTo(bSubkeys, bOldSubkeys.Length); } byte[] bReturn = new byte[bSecretKey.Length + bUserIDs.Length + bSubkeys.Length]; bSecretKey.CopyTo(bReturn, 0); bUserIDs.CopyTo(bReturn, bSecretKey.Length); bSubkeys.CopyTo(bReturn, bSecretKey.Length + bUserIDs.Length); return(bReturn); }
/// <summary> /// Parses the radix64 encoded representation of a transportable secret /// key given as an argument to populate the parameters of this. /// </summary> /// <param name="strRadix64">Radix64 representation of an transportable /// secret key</param> /// <exception cref="System.ArgumentException">Throws an /// ArgumentException if the radix64 string given as a parameter is /// not an transportable secret key.</exception> /// <remarks>No remarks</remarks> public void Parse(string strRadix64) { Packet[] pPackets = Packet.ParsePackets(strRadix64); int nCurrentPacket = 0; int nUserIDCounter = 0; try { // First we expect a PublicKeyPacket if (!(pPackets[0] is SecretKeyPacket)) { throw(new ArgumentException("The given packet is not in the required transportable secret key format!")); } this.PrimaryKey = (SecretKeyPacket)pPackets[nCurrentPacket++]; // Next we expect one or more userid packets while ((nCurrentPacket < pPackets.Length) && (pPackets[nCurrentPacket] is UserIDPacket)) { UserIDPacket uipUserID = (UserIDPacket)pPackets[nCurrentPacket++]; this.UserIDs.Add(uipUserID); nUserIDCounter++; } // we want at least 1 userid packet. if (nUserIDCounter == 0) { throw(new ArgumentException("The given packet is not in the required transportable secret key format!")); } // Finally we have zero or more subkeys while ((nCurrentPacket < pPackets.Length) && (pPackets[nCurrentPacket] is SecretKeyPacket)) { SecretKeyPacket skpSubKey = (SecretKeyPacket)pPackets[nCurrentPacket++]; this.SubKeys.Add(skpSubKey); } } catch (System.IndexOutOfRangeException) { if (nUserIDCounter == 0) { throw(new ArgumentException("The given packet is not in the required transportable secret key format!")); } } }
public void AddUserID(ulong lKeyID, string strName, string strEmail, string strPassphrase) { TransportableSecretKey tskKey = skrKeyRing.Find(lKeyID); TransportablePublicKey tpkKey = pkrKeyRing.Find(lKeyID, false); CertifiedUserID cuiUID = new CertifiedUserID(); UserIDPacket uipUID = new UserIDPacket(); uipUID.UserID = strName.Trim() + " <" + strEmail.Trim() + ">"; cuiUID.UserID = uipUID; SecretKeyPacket skpSignatureKey = tskKey.FindKey(AsymActions.Sign); SignaturePacket spSelfSig = new SignaturePacket(); spSelfSig.Version = SignaturePacketVersionNumbers.v4; spSelfSig.HashAlgorithm = HashAlgorithms.SHA1; spSelfSig.KeyID = skpSignatureKey.PublicKey.KeyID; spSelfSig.TimeCreated = DateTime.Now; cuiUID.Certificates = new System.Collections.ArrayList(); cuiUID.Sign(spSelfSig, skpSignatureKey, strPassphrase, tpkKey.PrimaryKey); tpkKey.Certifications.Add(cuiUID); tskKey.UserIDs.Add(uipUID); }
public void GenerateKey(string strName, string strEmail, string strKeyType, int iKeySize, long lExpiration, string strPassphrase) { if (strKeyType == "ElGamal/DSA") { System.Security.Cryptography.RandomNumberGenerator rngRand = System.Security.Cryptography.RandomNumberGenerator.Create(); // let's first create the encryption key BigInteger[][] biEncryptionKey = GenerateEncryptionKey(iKeySize); // now the signature key BigInteger[][] biSignatureKey = GenerateSignatureKey(); PublicKeyPacket pkpSignatureKey = new PublicKeyPacket(false); pkpSignatureKey.Algorithm = AsymAlgorithms.DSA; pkpSignatureKey.KeyMaterial = biSignatureKey[0]; pkpSignatureKey.TimeCreated = DateTime.Now; pkpSignatureKey.Version = PublicKeyPacketVersionNumbers.v4; SecretKeyPacket skpSignatureKey = new SecretKeyPacket(false); skpSignatureKey.SymmetricalAlgorithm = SymAlgorithms.AES256; skpSignatureKey.PublicKey = pkpSignatureKey; skpSignatureKey.InitialVector = new byte[CipherHelper.CipherBlockSize(SymAlgorithms.AES256)]; rngRand.GetBytes(skpSignatureKey.InitialVector); skpSignatureKey.EncryptKeyMaterial(biSignatureKey[1], strPassphrase); skpSignatureKey.PublicKey = pkpSignatureKey; PublicKeyPacket pkpEncryptionKey = new PublicKeyPacket(true); pkpEncryptionKey.Algorithm = AsymAlgorithms.ElGamal_Encrypt_Only; pkpEncryptionKey.KeyMaterial = biEncryptionKey[0]; pkpEncryptionKey.TimeCreated = DateTime.Now; pkpEncryptionKey.Version = PublicKeyPacketVersionNumbers.v4; SecretKeyPacket skpEncryptionKey = new SecretKeyPacket(true); skpEncryptionKey.SymmetricalAlgorithm = SymAlgorithms.AES256; skpEncryptionKey.PublicKey = pkpEncryptionKey; skpEncryptionKey.InitialVector = new byte[CipherHelper.CipherBlockSize(SymAlgorithms.AES256)]; rngRand.GetBytes(skpEncryptionKey.InitialVector); skpEncryptionKey.EncryptKeyMaterial(biEncryptionKey[1], strPassphrase); skpEncryptionKey.PublicKey = pkpEncryptionKey; CertifiedUserID cuiUID = new CertifiedUserID(); UserIDPacket uipUID = new UserIDPacket(); uipUID.UserID = strName.Trim() + " <" + strEmail.Trim() + ">"; cuiUID.UserID = uipUID; SignaturePacket spSelfSig = new SignaturePacket(); spSelfSig.Version = SignaturePacketVersionNumbers.v4; spSelfSig.HashAlgorithm = HashAlgorithms.SHA1; spSelfSig.KeyID = pkpSignatureKey.KeyID; spSelfSig.TimeCreated = DateTime.Now; SignatureSubPacket sspPrimaryUserID = new SignatureSubPacket(); sspPrimaryUserID.Type = SignatureSubPacketTypes.PrimaryUserID; sspPrimaryUserID.PrimaryUserID = true; spSelfSig.AddSubPacket(sspPrimaryUserID, true); SignatureSubPacket sspPreferedSymAlgos = new SignatureSubPacket(); sspPreferedSymAlgos.Type = SignatureSubPacketTypes.PreferedSymmetricAlgorithms; sspPreferedSymAlgos.PreferedSymAlgos = new SymAlgorithms[] { SymAlgorithms.AES256, SymAlgorithms.AES192, SymAlgorithms.AES256, SymAlgorithms.CAST5, SymAlgorithms.Triple_DES }; spSelfSig.AddSubPacket(sspPreferedSymAlgos, true); SignatureSubPacket sspPreferedHashAlgos = new SignatureSubPacket(); sspPreferedHashAlgos.Type = SignatureSubPacketTypes.PreferedHashAlgorithms; sspPreferedHashAlgos.PreferedHashAlgos = new HashAlgorithms[] { HashAlgorithms.SHA1 }; spSelfSig.AddSubPacket(sspPreferedHashAlgos, true); if (lExpiration != 0) { SignatureSubPacket sspExpiration = new SignatureSubPacket(); sspExpiration.Type = SignatureSubPacketTypes.SignatureExpirationTime; sspExpiration.SignatureExpirationTime = new DateTime(lExpiration); spSelfSig.AddSubPacket(sspExpiration, true); } cuiUID.Certificates = new System.Collections.ArrayList(); cuiUID.Sign(spSelfSig, skpSignatureKey, strPassphrase, pkpSignatureKey); CertifiedPublicSubkey cpsEncryptionKey = new CertifiedPublicSubkey(); cpsEncryptionKey.Subkey = pkpEncryptionKey; cpsEncryptionKey.SignKeyBindingSignature(pkpSignatureKey, skpSignatureKey, strPassphrase, new DateTime(lExpiration), true); TransportablePublicKey tpkPublicKey = new TransportablePublicKey(); tpkPublicKey.PrimaryKey = pkpSignatureKey; tpkPublicKey.SubKeys.Add(cpsEncryptionKey); tpkPublicKey.Certifications.Add(cuiUID); TransportableSecretKey tskSecretKey = new TransportableSecretKey(); tskSecretKey.PrimaryKey = skpSignatureKey; tskSecretKey.SubKeys.Add(skpEncryptionKey); tskSecretKey.UserIDs.Add(uipUID); this.pkrKeyRing.AddPublicKey(tpkPublicKey); this.skrKeyRing.AddSecretKey(tskSecretKey); pkrKeyRing.Save(); skrKeyRing.Save(); // it's an RSA key } else if (strKeyType == "RSA") { } }
public string GetSecretKeyProperties(ulong lKeyID) { TransportableSecretKey tskKey = skrKeyRing.Find(lKeyID); SecretKeyPacket skpKey = tskKey.PrimaryKey; XmlDocument xmlDoc = new XmlDocument(); XmlElement xmlSecretKey = xmlDoc.CreateElement("SecretKey"); xmlSecretKey.SetAttribute("keyid", "0x" + skpKey.PublicKey.KeyID.ToString("x")); xmlSecretKey.SetAttribute("fingerprint", skpKey.PublicKey.Fingerprint.ToString(16)); xmlSecretKey.SetAttribute("size", skpKey.PublicKey.KeyMaterial[0].bitCount().ToString()); xmlSecretKey.SetAttribute("algorithm", skpKey.PublicKey.Algorithm.ToString()); xmlSecretKey.SetAttribute("timecreated", skpKey.PublicKey.TimeCreated.Ticks.ToString()); XmlElement xmlUserIDs = xmlDoc.CreateElement("UserIDs"); XmlElement xmlUserID; IEnumerator ieUserIDs = tskKey.UserIDs.GetEnumerator(); while (ieUserIDs.MoveNext()) { if (!(ieUserIDs.Current is UserIDPacket)) { continue; } UserIDPacket uipUID = (UserIDPacket)ieUserIDs.Current; xmlUserID = xmlDoc.CreateElement("UserID"); xmlUserID.SetAttribute("name", uipUID.UserID); xmlUserIDs.AppendChild(xmlUserID); } xmlSecretKey.AppendChild(xmlUserIDs); XmlElement xmlSubkeys = xmlDoc.CreateElement("Subkeys"); XmlElement xmlSubkey; IEnumerator ieSubkeys = tskKey.SubKeys.GetEnumerator(); while (ieSubkeys.MoveNext()) { if (!(ieSubkeys.Current is SecretKeyPacket)) { continue; } SecretKeyPacket skpSubkey = (SecretKeyPacket)ieSubkeys.Current; xmlSubkey = xmlDoc.CreateElement("Subkey"); xmlSubkey.SetAttribute("keyid", "0x" + skpSubkey.PublicKey.KeyID.ToString("x")); xmlSubkey.SetAttribute("fingerprint", skpSubkey.PublicKey.Fingerprint.ToString(16)); xmlSubkey.SetAttribute("size", skpSubkey.PublicKey.KeyMaterial[0].bitCount().ToString()); xmlSubkey.SetAttribute("algorithm", skpSubkey.PublicKey.Algorithm.ToString()); xmlSubkeys.AppendChild(xmlSubkey); } xmlSecretKey.AppendChild(xmlSubkeys); xmlDoc.AppendChild(xmlSecretKey); return(xmlDoc.OuterXml); }
/// <summary> /// Parses the radix64 encoded representation of a transportable public /// key given as an argument to populate the parameters of this. /// </summary> /// <remarks>No remarks</remarks> /// <param name="strRadix64">Radix64 representation of an transportable /// public key</param> /// <exception cref="System.ArgumentException">Throws an /// ArgumentException if the radix64 string given as a parameter is /// not an transportable public key.</exception> public void Parse(string strRadix64) { Packet[] pPackets = Packet.ParsePackets(strRadix64); int nCurrentPacket = 0; int nUserIDCounter = 0; try { // First we expect a PublicKeyPacket if (!(pPackets[0] is PublicKeyPacket)) { throw(new ArgumentException("The given packet is not in the required transportable public key format!")); } this.PrimaryKey = (PublicKeyPacket)pPackets[nCurrentPacket++]; // Next we expect zero or more revocation signatures while ((nCurrentPacket < pPackets.Length) && (pPackets[nCurrentPacket] is SignaturePacket)) { SignaturePacket spRevocation = (SignaturePacket)pPackets[nCurrentPacket++]; if (spRevocation.SignatureType != SignatureTypes.KeyRevocationSignature) { throw(new ArgumentException("The given packet is not in the required transportable public key format!")); } this.RevocationSignatures.Add(spRevocation); } // Next in queue must be one or more UserID Packets while ((nCurrentPacket < pPackets.Length) && (pPackets[nCurrentPacket] is UserIDPacket)) { nUserIDCounter++; CertifiedUserID cuiUserID = new CertifiedUserID(); UserIDPacket uipUserID = (UserIDPacket)pPackets[nCurrentPacket++]; cuiUserID.UserID = uipUserID; // For every UserIDPacket we expect zero or more Signatures (Certificates) while ((nCurrentPacket < pPackets.Length) && (pPackets[nCurrentPacket] is SignaturePacket)) { SignaturePacket spCertificate = (SignaturePacket)pPackets[nCurrentPacket++]; if ((spCertificate.SignatureType != SignatureTypes.UserIDSignature) && (spCertificate.SignatureType != SignatureTypes.UserIDSignature_CasualVerification) && (spCertificate.SignatureType != SignatureTypes.UserIDSignature_NoVerification) && (spCertificate.SignatureType != SignatureTypes.UserIDSignature_PositivVerification)) { throw(new ArgumentException("The given packet is not in the required transportable public key format!")); } cuiUserID.Certificates.Add(spCertificate); } this.Certifications.Add(cuiUserID); } // There was no UserIDPacket. This is fatal!!! if (nUserIDCounter == 0) { throw(new ArgumentException("The given packet is not in the required transportable public key format!")); } // Finally we have zero or more subkeys while ((nCurrentPacket < pPackets.Length) && (pPackets[nCurrentPacket] is PublicKeyPacket)) { PublicKeyPacket pkpSubKey = (PublicKeyPacket)pPackets[nCurrentPacket++]; CertifiedPublicSubkey cpsSubKey = new CertifiedPublicSubkey(); cpsSubKey.Subkey = pkpSubKey; if ((nCurrentPacket < pPackets.Length) && (pPackets[nCurrentPacket] is SignaturePacket)) { SignaturePacket spKeySignature = (SignaturePacket)pPackets[nCurrentPacket++]; if (spKeySignature.SignatureType == SignatureTypes.SubkeyBindingSignature) { cpsSubKey.KeyBindingSignature = spKeySignature; } else if (spKeySignature.SignatureType == SignatureTypes.SubkeyRevocationSignature) { cpsSubKey.RevocationSignature = spKeySignature; } } else { throw(new ArgumentException("The given packet is not in the required transportable public key format!")); } if (nCurrentPacket < pPackets.Length) { if (pPackets[nCurrentPacket] is SignaturePacket) { SignaturePacket spSubkeyRev = (SignaturePacket)pPackets[nCurrentPacket++]; cpsSubKey.RevocationSignature = spSubkeyRev; } } this.SubKeys.Add(cpsSubKey); } } catch (System.IndexOutOfRangeException) { if (nUserIDCounter == 0) { throw(new ArgumentException("The given packet is not in the required transportable public key format!")); } } }
/// <summary> /// Parses a single packet out of the given binary /// data. Even if there are more than one packets in the byte /// array, only the first packet is returned. /// </summary> /// <param name="bBinaryData">A byte array containing a set /// of OpenPGP packets</param> /// <returns>Returns an single OpenPGP packets</returns> /// <remarks>No remarks</remarks> public virtual Packet ParsePacket(byte[] bBinaryData) { Packet pReturnPacket = new Packet(); if ((bBinaryData[0] & 0xC0) == 0xC0) { pfFormat = PacketFormats.New; } else if ((bBinaryData[0] & 0xC0) == 0x80) { pfFormat = PacketFormats.Old; } else { throw(new ArgumentException("This is not a valid OpenPGP Packet")); } if (pfFormat == PacketFormats.New) { int iBinaryDataPos = 2; ctContent = (ContentTypes)(bBinaryData[0] & 0x3F); lLength = bBinaryData[1]; bBody = new byte[0]; int iHeaderLength = 1; //partial body lengths while ((lLength > 223) && (lLength < 255)) { iHeaderLength++; int lPartialBody = 1 << ((int)(lLength & 0x1F)); int lOldLength = 0; if (bBody.Length > 0) { byte[] bOldBody = new byte[bBody.Length]; bBody.CopyTo(bOldBody, 0); bBody = new byte[bOldBody.Length + lPartialBody]; bOldBody.CopyTo(bBody, 0); lOldLength = bBody.Length; } else { bBody = new byte[lPartialBody]; } Array.Copy(bBinaryData, iBinaryDataPos, bBody, lOldLength, lPartialBody); lLength = bBinaryData[iBinaryDataPos + lPartialBody]; iBinaryDataPos += lPartialBody; } //partial bodies must end with a normal header! if (lLength < 192) { iHeaderLength++; bHeader = new byte[iHeaderLength]; if (bBody.Length == 0) { Array.Copy(bBinaryData, 0, bHeader, 0, 2); iBinaryDataPos = 1; } byte[] bOldBody = new byte[bBody.Length]; bBody.CopyTo(bOldBody, 0); bBody = new byte[bOldBody.Length + lLength]; bOldBody.CopyTo(bBody, 0); Array.Copy(bBinaryData, iBinaryDataPos + 1, bBody, bBody.Length - (int)lLength, (int)lLength); } else if ((lLength > 191) && (lLength < 224)) { iHeaderLength += 2; bHeader = new byte[iHeaderLength]; if (bBody.Length == 0) { Array.Copy(bBinaryData, 0, bHeader, 0, 3); iBinaryDataPos = 1; } lLength = ((bBinaryData[iBinaryDataPos++] - 192) << 8) + bBinaryData[iBinaryDataPos++] + 192; byte[] bOldBody = new byte[bBody.Length]; bBody.CopyTo(bOldBody, 0); bBody = new byte[bOldBody.Length + lLength]; bOldBody.CopyTo(bBody, 0); Array.Copy(bBinaryData, iBinaryDataPos, bBody, bBody.Length - (int)lLength, (int)lLength); } else if (lLength == 255) { iHeaderLength += 5; bHeader = new byte[iHeaderLength]; if (bBody.Length == 0) { Array.Copy(bBinaryData, 0, bHeader, 0, 6); } lLength = (bBinaryData[iBinaryDataPos++] << 24) ^ (bBinaryData[iBinaryDataPos++] << 16) ^ (bBinaryData[iBinaryDataPos++] << 8) ^ bBinaryData[iBinaryDataPos++]; byte[] bOldBody = new byte[bBody.Length]; bBody.CopyTo(bOldBody, 0); bBody = new byte[bOldBody.Length + lLength]; bOldBody.CopyTo(bBody, 0); Array.Copy(bBinaryData, iBinaryDataPos, bBody, bBody.Length - (int)lLength, (int)lLength); } } else { ctContent = (ContentTypes)((bBinaryData[0] & 0x3C) >> 2); switch (bBinaryData[0] & 0x03) { case 0: lLength = bBinaryData[1]; bHeader = new byte[2]; break; case 1: lLength = (bBinaryData[1] << 8) ^ (bBinaryData[2]); bHeader = new byte[3]; break; case 2: lLength = (bBinaryData[1] << 16) ^ (bBinaryData[2] << 8) ^ (bBinaryData[3]); bHeader = new byte[4]; break; case 3: throw new System.NotSupportedException("Packets of indetermined length are not supported due to security considerations!"); default: throw new System.ApplicationException("This is not a valid Packet!"); } bBody = new byte[lLength]; Array.Copy(bBinaryData, 0, bHeader, 0, bHeader.Length); Array.Copy(bBinaryData, bHeader.Length, bBody, 0, (int)lLength); } this.bIsUpdated = false; switch (ctContent) { case ContentTypes.AsymSessionKey: pReturnPacket = new AsymSessionKeyPacket(this); pReturnPacket = pReturnPacket.ParsePacket(bBody); break; case ContentTypes.Compressed: pReturnPacket = new CompressedDataPacket(this); pReturnPacket = pReturnPacket.ParsePacket(bBody); break; case ContentTypes.LiteralData: pReturnPacket = new LiteralDataPacket(this); pReturnPacket = pReturnPacket.ParsePacket(bBody); break; case ContentTypes.Marker: pReturnPacket = new Packet(this); //We can savly ignore Marker packets! //MessageBox.Show("This is a marker packet. It is not yet supported."); break; case ContentTypes.OnePassSignature: pReturnPacket = new OnePassSignaturePacket(this); //System.Windows.Forms.MessageBox.Show("This is a One Pass Signature Packet. It is not yet supported"); break; //Content is Public Key Packet case ContentTypes.PublicKey: pReturnPacket = new PublicKeyPacket(this); pReturnPacket = pReturnPacket.ParsePacket(bBody); break; //Content is Public Subkey Packet. Same format as Public Key Packet case ContentTypes.PublicSubkey: pReturnPacket = new PublicKeyPacket(this); pReturnPacket = pReturnPacket.ParsePacket(bBody); break; case ContentTypes.SecretKey: pReturnPacket = new SecretKeyPacket(this); pReturnPacket = pReturnPacket.ParsePacket(bBody); break; case ContentTypes.SecretSubkey: pReturnPacket = new SecretKeyPacket(this); pReturnPacket = pReturnPacket.ParsePacket(bBody); break; case ContentTypes.Signature: pReturnPacket = new SignaturePacket(this); pReturnPacket = pReturnPacket.ParsePacket(bBody); break; case ContentTypes.SymEncrypted: pReturnPacket = new SymmetricallyEncryptedDataPacket(this); pReturnPacket = pReturnPacket.ParsePacket(bBody); break; case ContentTypes.SymSessionKey: pReturnPacket = new SymSessionKeyPacket(this); pReturnPacket = pReturnPacket.ParsePacket(bBody); break; case ContentTypes.Trust: pReturnPacket = new Packet(this); // TODO - Remove the messagebox //System.Windows.Forms.MessageBox.Show("This is a Trust Packet. It is not yet supported"); break; case ContentTypes.UserID: pReturnPacket = new UserIDPacket(this); pReturnPacket = pReturnPacket.ParsePacket(bBody); break; default: pReturnPacket = new Packet(this); // TODO - Remove the messagebox System.Windows.Forms.MessageBox.Show("Sorry, but this is a packet I don't know about!"); break; } pReturnPacket.bIsUpdated = false; return(pReturnPacket); }