/// <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> /// Parses the packet given as byte array into the current /// class and returns this with the populated parameters. /// </summary> /// <param name="bData">A byte array containing an OpenPGP /// representation of the packet.</param> /// <returns>Returns an SecretKeyPacket that containes /// the parsed properties.</returns> /// <remarks>No remarks</remarks> public override Packet ParsePacket(byte[] bData) { PublicKey = new PublicKeyPacket(); PublicKey = (PublicKeyPacket)PublicKey.ParsePacket(bData); int iPos = this.PublicKey.Length; if (bData[iPos] == 255) { this.bIsEncrypted = true; iPos++; saSymmetricalAlgorithm = (SymAlgorithms)bData[iPos++]; //String2Key Specifier expected // a S2K specifier is at max 11 bytes long byte[] bS2k = new byte[11]; Array.Copy(bData, iPos, bS2k, 0, bS2k.Length); this.S2KSpecifier.ParseSpecifier(bS2k); iPos += S2KSpecifier.CraftContent().Length; //Parse Initial Vector int iBlockSize = CipherHelper.CipherBlockSize(saSymmetricalAlgorithm); this.InitialVector = new byte[iBlockSize]; Array.Copy(bData, iPos, bInitialVector, 0, iBlockSize); iPos += iBlockSize; //Parse Encrypted MPIs (including checksum!!!) this.bEncryptedKeyMaterial = new byte[bData.Length - iPos]; Array.Copy(bData, iPos, bEncryptedKeyMaterial, 0, bData.Length - iPos); } else if (bData[iPos] == 0) { this.bIsEncrypted = false; iPos++; //Parse unencrypted MPIs byte[] bMPIs = new byte[bData.Length - iPos - 2]; Array.Copy(bData, iPos, bMPIs, 0, bMPIs.Length); biDecryptedKeyMaterial = BigInteger.ParseMPIs(bMPIs); iPos += bMPIs.Length; this.sChecksum = (ushort)(bData[iPos++] << 8); this.sChecksum ^= (ushort)bData[iPos]; //validate checksum int iCurrentChecksum = 0; for (int i = 0; i < bMPIs.Length; i++) { iCurrentChecksum = (iCurrentChecksum + bMPIs[i]) % 65536; } if (iCurrentChecksum != sChecksum) { throw(new Exception("Key checksum is not correct. Someone played with the key?!")); } } else { //Encrypted in some strange way. We're not going //to support this throw(new Exception("This secret key is encrypted in some strange way. Sorry, but we're not going to support this. Get a real key!")); } this.bIsUpdated = false; return(this); }
/// <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); }