/// <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> /// 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); }