/// <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);
        }
Esempio n. 2
0
        /// <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);
        }