ReadSsh2PublicKeyData() public method

reads OpenSSH formatted public key blob and creates an AsymmetricKeyParameter object
public ReadSsh2PublicKeyData ( ) : AsymmetricKeyParameter
return Org.BouncyCastle.Crypto.AsymmetricKeyParameter
Example #1
0
        public override object Deserialize(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            using (var reader = new StreamReader(stream)) {
                var line = reader.ReadLine();
                line = line.Trim();
                var algoName = new string(line.TakeWhile(c => !char.IsWhiteSpace(c)).ToArray());
                line = line.Substring(algoName.Length).Trim();
                var data = new string(line.TakeWhile(c => !char.IsWhiteSpace(c)).ToArray());
                line = line.Substring(data.Length).Trim();
                var comment = line;

                PublicKeyAlgorithm algo;
                if (!TryParsePublicKeyAlgorithm(algoName, out algo))
                {
                    var message = string.Format("Unknown algorithm: {0}", algoName);
                    throw new KeyFormatterException(message);
                }

                var parser = new BlobParser(Util.FromBase64(data));
                OpensshCertificate cert;
                var publicKeyParams = parser.ReadSsh2PublicKeyData(out cert);
                var key             = new SshKey(SshVersion.SSH2, publicKeyParams, null, comment, cert);
                return(key);
            }
        }
Example #2
0
        OpensshCertificate ReadCertificate(BlobBuilder builder)
        {
            var serial = ReadUInt64();

            builder.AddUInt64(serial);
            var type = (Ssh2CertType)ReadUInt32();

            builder.AddUInt32((uint)type);
            var keyId = ReadString();

            builder.AddStringBlob(keyId);
            var validPrincipals = ReadBlob();

            builder.AddBlob(validPrincipals);
            var validAfter = ReadUInt64();

            builder.AddUInt64(validAfter);
            var validBefore = ReadUInt64();

            builder.AddUInt64(validBefore);
            var criticalOptions = ReadBlob();

            builder.AddBlob(criticalOptions);
            var extensions = ReadBlob();

            builder.AddBlob(extensions);
            var reserved = ReadBlob();

            builder.AddBlob(reserved);
            var signatureKey = ReadBlob();

            builder.AddBlob(signatureKey);
            var signature = ReadBlob();

            builder.AddBlob(signature);

            var principalsParser = new BlobParser(validPrincipals);
            var principalsList   = new List <string>();

            while (principalsParser.Stream.Position < principalsParser.Stream.Length)
            {
                principalsList.Add(principalsParser.ReadString());
            }
            var validAfterDateTime  = validAfter == ulong.MaxValue ? DateTime.MaxValue : epoch.AddSeconds(validAfter);
            var validBeforeDateTime = validBefore == ulong.MaxValue ? DateTime.MaxValue : epoch.AddSeconds(validBefore);
            var signatureKeyParser  = new BlobParser(signatureKey);
            OpensshCertificate unused;
            var sigKey = signatureKeyParser.ReadSsh2PublicKeyData(out unused);

            return(new OpensshCertificate(builder.GetBlob(), type, serial, keyId,
                                          principalsList, validAfterDateTime,
                                          validBeforeDateTime, criticalOptions,
                                          extensions, sigKey));
        }
        public override object Deserialize(Stream stream)
        {
            /* check for required parameters */
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            try {
                var reader    = new StreamReader(stream);
                var firstLine = reader.ReadLine();
                if (firstLine != MARK_BEGIN)
                {
                    throw new KeyFormatterException("Bad file format - does not have expected header.");
                }
                var base64String = new StringBuilder();
                while (true)
                {
                    var line = reader.ReadLine();
                    if (line == MARK_END)
                    {
                        break;
                    }
                    base64String.Append(line);
                }

                /* reading unencrypted part */
                BlobParser parser = new BlobParser(Util.FromBase64(base64String.ToString()));

                var magicBytes = parser.ReadBytes((uint)AUTH_MAGIC.Length);
                if (Encoding.UTF8.GetString(magicBytes) != AUTH_MAGIC)
                {
                    throw new KeyFormatterException("Bad data - missing AUTH_MAGIC.");
                }

                var ciphername = parser.ReadString();
                if (!IsSupportCipher(ciphername))
                {
                    throw new KeyFormatterException("Unsupported cyphername: " + ciphername);
                }

                var kdfname = parser.ReadString();
                if (kdfname != KDFNAME_BCRYPT && kdfname != KDFNAME_NONE)
                {
                    throw new KeyFormatterException("Unsupported kdfname: " + ciphername);
                }
                if (kdfname == KDFNAME_NONE && ciphername != CIPHERNAME_NONE)
                {
                    throw new KeyFormatterException("Invalid format.");
                }

                var kdfoptions = parser.ReadBlob();
                var keyCount   = parser.ReadUInt32();
                if (keyCount != 1)
                {
                    throw new KeyFormatterException("Only one key allowed.");
                }

                var publicKeys = new List <byte[]>();
                for (int i = 0; i < keyCount; i++)
                {
                    publicKeys.Add(parser.ReadBlob());
                }
                var privateKeys = parser.ReadBlob();

                var keyAndIV = new byte[32 + 16];
                if (kdfname == KDFNAME_BCRYPT)
                {
                    var kdfOptionsParser = new BlobParser(kdfoptions);
                    var salt             = kdfOptionsParser.ReadBlob();
                    var rounds           = kdfOptionsParser.ReadUInt32();

                    var passphrase      = GetPassphraseCallbackMethod(null);
                    var passphraseChars = new char[passphrase.Length];
                    var passphrasePtr   = Marshal.SecureStringToGlobalAllocUnicode(passphrase);
                    for (int i = 0; i < passphrase.Length; i++)
                    {
                        passphraseChars[i] = (char)Marshal.ReadInt16(passphrasePtr, i * 2);
                    }
                    Marshal.ZeroFreeGlobalAllocUnicode(passphrasePtr);
                    BCrypt.HashUsingOpensshBCryptPbkdf(passphraseChars, salt, ref keyAndIV, rounds);
                    Array.Clear(passphraseChars, 0, passphraseChars.Length);
                }

                var key = new byte[32];
                Array.Copy(keyAndIV, key, key.Length);
                var iv = new byte[16];
                Array.Copy(keyAndIV, key.Length, iv, 0, iv.Length);

                switch (ciphername)
                {
                case CIPHERNAME_AES256_CBC:
                    var aes = Aes.Create();
                    aes.KeySize = 256;
                    aes.Mode    = CipherMode.CBC;
                    aes.Padding = PaddingMode.None;
                    aes.Key     = key;
                    aes.IV      = iv;

                    if (privateKeys.Length < aes.BlockSize / 8 || privateKeys.Length % (aes.BlockSize / 8) != 0)
                    {
                        throw new KeyFormatterException("Bad private key encrypted length.");
                    }

                    using (ICryptoTransform decryptor = aes.CreateDecryptor()) {
                        privateKeys = Util.GenericTransform(decryptor, privateKeys);
                    }
                    aes.Clear();
                    break;

                case CIPHERNAME_AES256_CTR:
                    var ctrCipher = CipherUtilities.GetCipher("AES/CTR/NoPadding");
                    ctrCipher.Init(false, new ParametersWithIV(new KeyParameter(key), iv));
                    privateKeys = ctrCipher.DoFinal(privateKeys);
                    break;
                }

                parser = new BlobParser(privateKeys);

                var checkint1 = parser.ReadUInt32();
                var checkint2 = parser.ReadUInt32();
                if (checkint1 != checkint2)
                {
                    throw new KeyFormatterException("checkint does not match in private key.");
                }
                var keys = new List <SshKey>();
                for (int i = 0; i < keyCount; i++)
                {
                    OpensshCertificate cert;
                    var publicKey = parser.ReadSsh2PublicKeyData(out cert);
                    var keyPair   = parser.ReadSsh2KeyData(publicKey);
                    var comment   = parser.ReadString();
                    var sshKey    = new SshKey(SshVersion.SSH2, keyPair, comment, cert);
                    keys.Add(sshKey);
                }
                return(keys[0]);
            } catch (KeyFormatterException) {
                throw;
            } catch (Exception ex) {
                throw new KeyFormatterException("see inner exception", ex);
            }
        }
Example #4
0
        /// <summary>
        /// Answers the message.
        /// </summary>
        /// <param name='messageStream'>Message stream.</param>
        /// <param name="process">The calling process or <c>null</c> if the process
        /// could not be obtained.</param>
        /// <remarks>code based on winpgnt.c from PuTTY source code</remarks>
        public void AnswerMessage(Stream messageStream, Process process = null)
        {
            if (messageStream.CanTimeout)
            {
                messageStream.ReadTimeout = 5000;
            }
            var        messageParser   = new BlobParser(messageStream);
            var        responseBuilder = new BlobBuilder();
            BlobHeader header;

            try {
                header = messageParser.ReadHeader();

                if (MessageReceived != null)
                {
                    var eventArgs = new MessageReceivedEventArgs(header);
                    MessageReceived(this, eventArgs);
                    if (eventArgs.Fail)
                    {
                        throw new Exception();
                    }
                }
            } catch (Exception) {
                header         = new BlobHeader();
                header.Message = Message.UNKNOWN;
                // this will cause the switch statement below to use the default case
                // which returns an error to the stream.
            }

            switch (header.Message)
            {
            case Message.SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
                /*
                 * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
                 */
                try {
                    if (header.BlobLength > 1)
                    {
                        // ruby net-ssh tries to send a SSH2_AGENT_REQUEST_VERSION message
                        // which has the same id number as SSH1_AGENTC_REQUEST_RSA_IDENTITIES
                        // with a string tacked on. We need to read the string from the
                        // stream, but it is not used for anything.
                        messageParser.ReadString();
                    }
                    var keyList = ListKeys(SshVersion.SSH1);
                    if (FilterKeyListCallback != null)
                    {
                        keyList = FilterKeyListCallback(keyList);
                    }
                    foreach (SshKey key in keyList)
                    {
                        responseBuilder.AddBytes(key.GetPublicKeyBlob());
                        responseBuilder.AddStringBlob(key.Comment);
                    }
                    responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_IDENTITIES_ANSWER,
                                                 keyList.Count);
                    // TODO may want to check that there is enough room in the message stream
                    break; // succeeded
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH2_AGENTC_REQUEST_IDENTITIES:
                /*
                 * Reply with SSH2_AGENT_IDENTITIES_ANSWER.
                 */
                try {
                    var keyList = ListKeys(SshVersion.SSH2);
                    if (FilterKeyListCallback != null)
                    {
                        keyList = FilterKeyListCallback(keyList);
                    }
                    foreach (SshKey key in keyList)
                    {
                        responseBuilder.AddBlob(key.GetPublicKeyBlob());
                        responseBuilder.AddStringBlob(key.Comment);
                    }
                    responseBuilder.InsertHeader(Message.SSH2_AGENT_IDENTITIES_ANSWER,
                                                 keyList.Count);
                    // TODO may want to check that there is enough room in the message stream
                    break; // succeeded
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH1_AGENTC_RSA_CHALLENGE:
                /*
                 * Reply with either SSH1_AGENT_RSA_RESPONSE or
                 * SSH_AGENT_FAILURE, depending on whether we have that key
                 * or not.
                 */

                try {
                    //Reading publicKey information
                    var publicKeyParams = messageParser.ReadSsh1PublicKeyData(true);

                    //Searching for Key here
                    var matchingKey = mKeyList.Where(key => key.Version == SshVersion.SSH1 &&
                                                     (key.GetPublicKeyParameters().Equals(publicKeyParams))).Single();

                    //Reading challenge
                    var encryptedChallenge = messageParser.ReadSsh1BigIntBlob();
                    var sessionId          = messageParser.ReadBytes(16);

                    //Checking responseType field
                    if (messageParser.ReadUInt32() != 1)
                    {
                        goto default; //responseType !=1  is not longer supported
                    }

                    //Answering to the challenge
                    var engine = new Pkcs1Encoding(new RsaEngine());
                    engine.Init(false /* decrypt */, matchingKey.GetPrivateKeyParameters());

                    var decryptedChallenge = engine.ProcessBlock(encryptedChallenge,
                                                                 0, encryptedChallenge.Length);

                    using (MD5 md5 = MD5.Create()) {
                        var md5Buffer = new byte[48];
                        decryptedChallenge.CopyTo(md5Buffer, 0);
                        sessionId.CopyTo(md5Buffer, 32);

                        responseBuilder.AddBytes(md5.ComputeHash(md5Buffer));
                        responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_RESPONSE);
                        break;
                    }
                } catch (InvalidOperationException) {
                    // this is expected if there is not a matching key
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }

                goto default; // failed

            case Message.SSH2_AGENTC_SIGN_REQUEST:
                /*
                 * Reply with either SSH2_AGENT_SIGN_RESPONSE or SSH_AGENT_FAILURE,
                 * depending on whether we have that key or not.
                 */
                try {
                    var keyBlob = messageParser.ReadBlob();
                    var reqData = messageParser.ReadBlob();
                    var flags   = new SignRequestFlags();
                    try {
                        // usually, there are no flags, so parser will throw
                        flags = (SignRequestFlags)messageParser.ReadUInt32();
                    } catch { }

                    var matchingKey =
                        mKeyList.Where(key => key.Version == SshVersion.SSH2 &&
                                       key.GetPublicKeyBlob().SequenceEqual(keyBlob)).First();
                    var confirmConstraints = matchingKey.Constraints
                                             .Where(constraint => constraint.Type ==
                                                    KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM);
                    if (confirmConstraints.Count() > 0)
                    {
                        if (!ConfirmUserPermissionCallback.Invoke(matchingKey, process))
                        {
                            goto default;
                        }
                    }

                    /* create signature */
                    var signKey = matchingKey;
                    var signer  = signKey.GetSigner();
                    var algName = signKey.Algorithm.GetIdentifierString();
                    signer.Init(true, signKey.GetPrivateKeyParameters());
                    signer.BlockUpdate(reqData, 0, reqData.Length);
                    byte[] signature = signer.GenerateSignature();
                    signature = signKey.FormatSignature(signature);
                    BlobBuilder signatureBuilder = new BlobBuilder();
                    if (!flags.HasFlag(SignRequestFlags.SSH_AGENT_OLD_SIGNATURE))
                    {
                        signatureBuilder.AddStringBlob(algName);
                    }
                    signatureBuilder.AddBlob(signature);
                    responseBuilder.AddBlob(signatureBuilder.GetBlob());
                    responseBuilder.InsertHeader(Message.SSH2_AGENT_SIGN_RESPONSE);
                    try {
                        KeyUsed(this, new KeyUsedEventArgs(signKey, process));
                    } catch { }
                    break; // succeeded
                } catch (InvalidOperationException) {
                    // this is expected if there is not a matching key
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failure

            case Message.SSH1_AGENTC_ADD_RSA_IDENTITY:
            case Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED:
                /*
                 * Add to the list and return SSH_AGENT_SUCCESS, or
                 * SSH_AGENT_FAILURE if the key was malformed.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                bool ssh1constrained = (header.Message == Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED);

                try {
                    var publicKeyParams = messageParser.ReadSsh1PublicKeyData(false);
                    var keyPair         = messageParser.ReadSsh1KeyData(publicKeyParams);

                    SshKey key = new SshKey(SshVersion.SSH1, keyPair);
                    key.Comment = messageParser.ReadString();
                    key.Source  = "External client";

                    if (ssh1constrained)
                    {
                        while (messageStream.Position < header.BlobLength + 4)
                        {
                            KeyConstraint constraint = new KeyConstraint();
                            constraint.Type = (KeyConstraintType)messageParser.ReadUInt8();
                            if (constraint.Type ==
                                KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME)
                            {
                                constraint.Data = messageParser.ReadUInt32();
                            }
                            key.AddConstraint(constraint);
                        }
                    }
                    AddKey(key);
                    responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                    break;
                } catch (CallbackNullException) {
                    // this is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }

                goto default; // failed

            case Message.SSH2_AGENTC_ADD_IDENTITY:
            case Message.SSH2_AGENTC_ADD_ID_CONSTRAINED:
                /*
                 * Add to the list and return SSH_AGENT_SUCCESS, or
                 * SSH_AGENT_FAILURE if the key was malformed.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                bool constrained = (header.Message ==
                                    Message.SSH2_AGENTC_ADD_ID_CONSTRAINED);

                try {
                    OpensshCertificate cert;
                    var    publicKeyParams = messageParser.ReadSsh2PublicKeyData(out cert);
                    var    keyPair         = messageParser.ReadSsh2KeyData(publicKeyParams);
                    SshKey key             = new SshKey(SshVersion.SSH2, keyPair, null, cert);
                    key.Comment = messageParser.ReadString();
                    key.Source  = "External client";

                    if (constrained)
                    {
                        while (messageStream.Position < header.BlobLength + 4)
                        {
                            KeyConstraint constraint = new KeyConstraint();
                            constraint.Type =
                                (KeyConstraintType)messageParser.ReadUInt8();
                            if (constraint.Type ==
                                KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME)
                            {
                                constraint.Data = messageParser.ReadUInt32();
                            }
                            key.AddConstraint(constraint);
                        }
                    }
                    AddKey(key);
                    responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                    break; // success!
                } catch (CallbackNullException) {
                    // this is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY:
            case Message.SSH2_AGENTC_REMOVE_IDENTITY:
                /*
                 * Remove from the list and return SSH_AGENT_SUCCESS, or
                 * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
                 * start with.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                SshVersion removeVersion;
                byte[]     rKeyBlob;
                if (header.Message == Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY)
                {
                    removeVersion = SshVersion.SSH1;
                    rKeyBlob      = messageParser.ReadBytes(header.BlobLength - 1);
                }
                else if (header.Message == Message.SSH2_AGENTC_REMOVE_IDENTITY)
                {
                    removeVersion = SshVersion.SSH2;
                    rKeyBlob      = messageParser.ReadBlob();
                }
                else
                {
                    Debug.Fail("Should not get here.");
                    goto default;
                }

                try {
                    var matchingKey        = mKeyList.Get(removeVersion, rKeyBlob);
                    var startKeyListLength = mKeyList.Count;
                    RemoveKey(matchingKey);
                    // only succeed if key was removed
                    if (mKeyList.Count == startKeyListLength - 1)
                    {
                        responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                        break; //success!
                    }
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
            case Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
                /*
                 * Remove all SSH-1 or SSH-2 keys.
                 */

                if (IsLocked)
                {
                    goto default;
                }

                SshVersion removeAllVersion;
                if (header.Message == Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES)
                {
                    removeAllVersion = SshVersion.SSH1;
                }
                else if (header.Message == Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES)
                {
                    removeAllVersion = SshVersion.SSH2;
                }
                else
                {
                    Debug.Fail("Should not get here.");
                    goto default;
                }

                try {
                    RemoveAllKeys(removeAllVersion);
                    responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                    break; //success!
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default; // failed

            case Message.SSH_AGENTC_LOCK:
                try {
                    var passphrase = new PinnedArray <byte>(messageParser.ReadBlob());
                    try {
                        Lock(passphrase.Data);
                    } finally {
                        passphrase.Clear();
                    }
                    if (IsLocked)
                    {
                        responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                        break;
                    }
                } catch (AgentLockedException) {
                    // This is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default;

            case Message.SSH_AGENTC_UNLOCK:
                try {
                    var passphrase = new PinnedArray <byte>(messageParser.ReadBlob());
                    try {
                        Unlock(passphrase.Data);
                    } finally {
                        passphrase.Clear();
                    }
                    if (!IsLocked)
                    {
                        responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
                        break;
                    }
                } catch (AgentLockedException) {
                    // This is expected
                } catch (PassphraseException) {
                    // This is expected
                } catch (Exception ex) {
                    Debug.Fail(ex.ToString());
                }
                goto default;

            default:
                responseBuilder.Clear();
                responseBuilder.InsertHeader(Message.SSH_AGENT_FAILURE);
                break;
            }
            /* write response to stream */
            if (messageStream.CanSeek)
            {
                messageStream.Position = 0;
            }
            messageStream.Write(responseBuilder.GetBlob(), 0, responseBuilder.Length);
            messageStream.Flush();
        }
Example #5
0
        public override object Deserialize(Stream stream)
        {
            /* check for required parameters */
            if (stream == null) {
                throw new ArgumentNullException("stream");
            }

            try {
                var reader = new StreamReader(stream);
                var firstLine = reader.ReadLine();
                if (firstLine != MARK_BEGIN) {
                    throw new KeyFormatterException("Bad file format - does not have expected header.");
                }
                var base64String = new StringBuilder();
                while (true) {
                    var line = reader.ReadLine();
                    if (line == MARK_END) {
                        break;
                    }
                    base64String.Append(line);
                }

                /* reading unencrypted part */
                BlobParser parser = new BlobParser(Util.FromBase64(base64String.ToString()));

                var magicBytes = parser.ReadBytes((uint)AUTH_MAGIC.Length);
                if (Encoding.UTF8.GetString(magicBytes) != AUTH_MAGIC) {
                    throw new KeyFormatterException("Bad data - missing AUTH_MAGIC.");
                }

                var ciphername = parser.ReadString();
                if (ciphername != CIPHERNAME_AES256_CBC && ciphername != CIPHERNAME_NONE) {
                    throw new KeyFormatterException("Unsupported cyphername: " + ciphername);
                }

                var kdfname = parser.ReadString();
                if (kdfname != KDFNAME_BCRYPT && kdfname != KDFNAME_NONE) {
                    throw new KeyFormatterException("Unsupported kdfname: " + ciphername);
                }
                if (kdfname == KDFNAME_NONE && ciphername != CIPHERNAME_NONE) {
                    throw new KeyFormatterException("Invalid format.");
                }

                var kdfoptions = parser.ReadBlob();
                var keyCount = parser.ReadInt();
                if (keyCount != 1) {
                    throw new KeyFormatterException("Only one key allowed.");
                }

                var publicKeys = new List<byte[]>();
                for (int i = 0; i < keyCount; i++) {
                    publicKeys.Add(parser.ReadBlob());
                }
                var privateKeys = parser.ReadBlob();

                if (ciphername == CIPHERNAME_AES256_CBC) {
                    Aes aes = Aes.Create();
                    aes.KeySize = 256;
                    aes.Mode = CipherMode.CBC;
                    aes.Padding = PaddingMode.None;

                    if (privateKeys.Length < aes.BlockSize / 8 || privateKeys.Length % (aes.BlockSize / 8) != 0) {
                        throw new KeyFormatterException("Bad private key encrypted length.");
                    }

                    var keyAndIV = new byte[aes.Key.Length + aes.IV.Length];
                    if (kdfname == KDFNAME_BCRYPT) {
                        var kdfOptionsParser = new BlobParser(kdfoptions);
                        var salt = kdfOptionsParser.ReadBlob();
                        var rounds = kdfOptionsParser.ReadInt();

                        var passphrase = GetPassphraseCallbackMethod(null);
                        var passphraseChars = new char[passphrase.Length];
                        IntPtr passphrasePtr = Marshal.SecureStringToGlobalAllocUnicode(passphrase);
                        for (int i = 0; i < passphrase.Length; i++) {
                            passphraseChars[i] = (char)Marshal.ReadInt16(passphrasePtr, i * 2);
                        }
                        Marshal.ZeroFreeGlobalAllocUnicode(passphrasePtr);
                        BCrypt.HashUsingOpensshBCryptPbkdf(passphraseChars, salt, ref keyAndIV, rounds);
                        Array.Clear(passphraseChars, 0, passphraseChars.Length);
                    }

                    // Array.Copy to aes.Key and aes.IV directly does not work!
                    var key = new byte[aes.Key.Length];
                    Array.Copy(keyAndIV, key, key.Length);
                    aes.Key = key;
                    var iv = new byte[aes.IV.Length];
                    Array.Copy(keyAndIV, key.Length, iv, 0, iv.Length);
                    aes.IV = iv;
                    using (ICryptoTransform decryptor = aes.CreateDecryptor()) {
                        privateKeys = Util.GenericTransform(decryptor, privateKeys);
                    }
                    aes.Clear();
                }

                parser = new BlobParser(privateKeys);

                var checkint1 = parser.ReadInt();
                var checkint2 = parser.ReadInt();
                if (checkint1 != checkint2) {
                    throw new KeyFormatterException("checkint does not match in private key.");
                }
                var keys = new List<SshKey>();
                for (int i = 0; i < keyCount; i++) {
                    var publicKey = parser.ReadSsh2PublicKeyData();
                    var keyPair = parser.ReadSsh2KeyData(publicKey);
                    var comment = parser.ReadString();
                    var key = new SshKey(SshVersion.SSH2, keyPair, comment);
                    keys.Add(key);
                }
                return keys[0];
            } catch (KeyFormatterException) {
                throw;
            } catch (Exception ex) {
                throw new KeyFormatterException("see inner exception", ex);
            }
        }
Example #6
0
        /// <summary>
        /// reads OpenSSH formatted public key blob and creates
        /// an AsymmetricKeyParameter object
        /// </summary>
        /// <returns>AsymmetricKeyParameter containing the public key</returns>
        public AsymmetricKeyParameter ReadSsh2PublicKeyData(out OpensshCertificate cert)
        {
            cert = null;
            var algorithm   = Encoding.UTF8.GetString(ReadBlob());
            var certBuilder = new BlobBuilder();

            certBuilder.AddStringBlob(algorithm);

            switch (algorithm)
            {
            case PublicKeyAlgorithmExt.ALGORITHM_RSA_KEY: {
                var n = new BigInteger(1, ReadBlob()); // modulus
                var e = new BigInteger(1, ReadBlob()); // exponent
                if (n.BitLength < e.BitLength)
                {
                    // In some cases, the modulus is first. We can always tell because
                    // it is significantly larget than the exponent.
                    return(new RsaKeyParameters(false, e, n));
                }
                return(new RsaKeyParameters(false, n, e));
            }

            case PublicKeyAlgorithmExt.ALGORITHM_RSA_CERT_V1: {
                var nonce = ReadBlob();
                if (nonce.Length != 32)
                {
                    // we are being called from SSH2_AGENTC_ADD_IDENTITY and this blob
                    // is the whole certificate, not the nonce
                    var certParser = new BlobParser(nonce);
                    return(certParser.ReadSsh2PublicKeyData(out cert));
                }
                else
                {
                    certBuilder.AddBlob(nonce);
                    var e = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(e);
                    var n = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(n);

                    cert = ReadCertificate(certBuilder);

                    return(new RsaKeyParameters(false, n, e));
                }
            }

            case PublicKeyAlgorithmExt.ALGORITHM_DSA_KEY: {
                var p = new BigInteger(1, ReadBlob());
                var q = new BigInteger(1, ReadBlob());
                var g = new BigInteger(1, ReadBlob());
                var y = new BigInteger(1, ReadBlob());

                var dsaParams = new DsaParameters(p, q, g);
                return(new DsaPublicKeyParameters(y, dsaParams));
            }

            case PublicKeyAlgorithmExt.ALGORITHM_DSA_CERT_V1: {
                var nonce = ReadBlob();
                if (nonce.Length != 32)
                {
                    // we are being called from SSH2_AGENTC_ADD_IDENTITY and this blob
                    // is the whole certificate, not the nonce
                    var certParser = new BlobParser(nonce);
                    return(certParser.ReadSsh2PublicKeyData(out cert));
                }
                else
                {
                    certBuilder.AddBlob(nonce);
                    var p = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(p);
                    var q = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(q);
                    var g = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(g);
                    var y = new BigInteger(1, ReadBlob());
                    certBuilder.AddBigIntBlob(y);

                    cert = ReadCertificate(certBuilder);

                    var dsaParams = new DsaParameters(p, q, g);
                    return(new DsaPublicKeyParameters(y, dsaParams));
                }
            }

            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP256_KEY:
            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP384_KEY:
            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP521_KEY: {
                var curveName = ReadString();
                var publicKey = ReadBlob();

                var x9Params     = SecNamedCurves.GetByName(EcCurveToAlgorithm(curveName));
                var domainParams = new ECDomainParameters(x9Params.Curve, x9Params.G, x9Params.N, x9Params.H);
                var point        = x9Params.Curve.DecodePoint(publicKey);
                return(new ECPublicKeyParameters(point, domainParams));
            }

            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP256_CERT_V1:
            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP384_CERT_V1:
            case PublicKeyAlgorithmExt.ALGORITHM_ECDSA_SHA2_NISTP521_CERT_V1: {
                var nonce = ReadBlob();
                if (nonce.Length != 32)
                {
                    // we are being called from SSH2_AGENTC_ADD_IDENTITY and this blob
                    // is the whole certificate, not the nonce
                    var certParser = new BlobParser(nonce);
                    return(certParser.ReadSsh2PublicKeyData(out cert));
                }
                else
                {
                    certBuilder.AddBlob(nonce);
                    var curveName = ReadString();
                    certBuilder.AddStringBlob(curveName);
                    var publicKey = ReadBlob();
                    certBuilder.AddBlob(publicKey);

                    cert = ReadCertificate(certBuilder);

                    var x9Params     = SecNamedCurves.GetByName(EcCurveToAlgorithm(curveName));
                    var domainParams = new ECDomainParameters(x9Params.Curve, x9Params.G, x9Params.N, x9Params.H);
                    var point        = x9Params.Curve.DecodePoint(publicKey);

                    return(new ECPublicKeyParameters(point, domainParams));
                }
            }

            case PublicKeyAlgorithmExt.ALGORITHM_ED25519: {
                var publicKey = ReadBlob();
                return(new Ed25519PublicKeyParameter(publicKey));
            }

            case PublicKeyAlgorithmExt.ALGORITHM_ED25519_CERT_V1: {
                var nonce = ReadBlob();
                if (nonce.Length != 32)
                {
                    // we are being called from SSH2_AGENTC_ADD_IDENTITY and this blob
                    // is the whole certificate, not the nonce
                    var certParser = new BlobParser(nonce);
                    certParser.ReadSsh2PublicKeyData(out cert);
                    var publicKey = ReadBlob();

                    return(new Ed25519PublicKeyParameter(publicKey));
                }
                else
                {
                    certBuilder.AddBlob(nonce);
                    var publicKey = ReadBlob();
                    certBuilder.AddBlob(publicKey);

                    cert = ReadCertificate(certBuilder);

                    return(new Ed25519PublicKeyParameter(publicKey));
                }
            }

            default:
                // unsupported encryption algorithm
                throw new Exception("Unsupported algorithm");
            }
        }
Example #7
0
        /// <summary>
        /// Answers the message.
        /// </summary>
        /// <param name='messageStream'>Message stream.</param>
        /// <param name="process">The calling process or <c>null</c> if the process
        /// could not be obtained.</param>
        /// <remarks>code based on winpgnt.c from PuTTY source code</remarks>
        public void AnswerMessage(Stream messageStream, Process process = null)
        {
            if (messageStream.CanTimeout) {
            messageStream.ReadTimeout = 5000;
              }
              var messageParser = new BlobParser(messageStream);
              var responseBuilder = new BlobBuilder();
              BlobHeader header;
              try {
            header = messageParser.ReadHeader();

            if (MessageReceived != null) {
              var eventArgs = new MessageReceivedEventArgs(header);
              MessageReceived(this, eventArgs);
              if (eventArgs.Fail) {
            throw new Exception ();
              }
            }
              } catch (Exception) {
            header = new BlobHeader();
            header.Message = Message.UNKNOWN;
            // this will cause the switch statement below to use the default case
            // which returns an error to the stream.
              }

              switch (header.Message) {
            case Message.SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
              /*
               * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
               */
              try {
            if (header.BlobLength > 1) {
              // ruby net-ssh tries to send a SSH2_AGENT_REQUEST_VERSION message
              // which has the same id number as SSH1_AGENTC_REQUEST_RSA_IDENTITIES
              // with a string tacked on. We need to read the string from the
              // stream, but it is not used for anything.
              messageParser.ReadString ();
            }
            var keyList = ListKeys(SshVersion.SSH1);
            if (FilterKeyListCallback != null) {
              keyList = FilterKeyListCallback(keyList);
            }
            foreach (SshKey key in keyList) {
              responseBuilder.AddBytes(key.GetPublicKeyBlob());
              responseBuilder.AddStringBlob(key.Comment);
            }
            responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_IDENTITIES_ANSWER,
              keyList.Count);
            // TODO may want to check that there is enough room in the message stream
            break; // succeeded
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failed

            case Message.SSH2_AGENTC_REQUEST_IDENTITIES:
              /*
               * Reply with SSH2_AGENT_IDENTITIES_ANSWER.
               */
              try {
            var keyList = ListKeys(SshVersion.SSH2);
            if (FilterKeyListCallback != null) {
              keyList = FilterKeyListCallback(keyList);
            }
            foreach (SshKey key in keyList) {
              responseBuilder.AddBlob(key.GetPublicKeyBlob());
              responseBuilder.AddStringBlob(key.Comment);
            }
            responseBuilder.InsertHeader(Message.SSH2_AGENT_IDENTITIES_ANSWER,
              keyList.Count);
            // TODO may want to check that there is enough room in the message stream
            break; // succeeded
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failed

            case Message.SSH1_AGENTC_RSA_CHALLENGE:
              /*
               * Reply with either SSH1_AGENT_RSA_RESPONSE or
               * SSH_AGENT_FAILURE, depending on whether we have that key
               * or not.
               */

              try {
            //Reading publicKey information
            var publicKeyParams = messageParser.ReadSsh1PublicKeyData(true);

            //Searching for Key here
            var matchingKey = mKeyList.Where(key => key.Version == SshVersion.SSH1
                && (key.GetPublicKeyParameters().Equals(publicKeyParams))).Single();

            //Reading challenge
            var encryptedChallenge = messageParser.ReadSsh1BigIntBlob();
            var sessionId = messageParser.ReadBytes(16);

            //Checking responseType field
            if (messageParser.ReadInt() != 1) {
              goto default; //responseType !=1  is not longer supported
            }

            //Answering to the challenge
            var engine = new Pkcs1Encoding(new RsaEngine());
            engine.Init(false /* decrypt */, matchingKey.GetPrivateKeyParameters());

            var decryptedChallenge = engine.ProcessBlock(encryptedChallenge,
                0, encryptedChallenge.Length);

            using (MD5 md5 = MD5.Create()) {
              var md5Buffer = new byte[48];
              decryptedChallenge.CopyTo(md5Buffer, 0);
              sessionId.CopyTo(md5Buffer, 32);

              responseBuilder.AddBytes(md5.ComputeHash(md5Buffer));
              responseBuilder.InsertHeader(Message.SSH1_AGENT_RSA_RESPONSE);
              break;
            }
              } catch (InvalidOperationException) {
            // this is expected if there is not a matching key
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }

              goto default; // failed

            case Message.SSH2_AGENTC_SIGN_REQUEST:
              /*
               * Reply with either SSH2_AGENT_SIGN_RESPONSE or SSH_AGENT_FAILURE,
               * depending on whether we have that key or not.
               */
              try {
            var keyBlob = messageParser.ReadBlob();
            var reqData = messageParser.ReadBlob();
            var flags = new SignRequestFlags();
            try {
              // usually, there are no flags, so parser will throw
              flags = (SignRequestFlags)messageParser.ReadInt();
            } catch { }

            var matchingKey =
              mKeyList.Where(key => key.Version == SshVersion.SSH2 &&
              key.GetPublicKeyBlob().SequenceEqual(keyBlob)).First();
            var confirmConstraints = matchingKey.Constraints
              .Where(constraint => constraint.Type ==
                KeyConstraintType.SSH_AGENT_CONSTRAIN_CONFIRM);
            if (confirmConstraints.Count() > 0) {
              if (!ConfirmUserPermissionCallback.Invoke(matchingKey, process)) {
                goto default;
              }
            }

            /* create signature */
            var signKey = matchingKey;
            var signer = signKey.GetSigner();
            var algName = signKey.Algorithm.GetIdentifierString();
            signer.Init(true, signKey.GetPrivateKeyParameters());
            signer.BlockUpdate(reqData, 0, reqData.Length);
            byte[] signature = signer.GenerateSignature();
            signature = signKey.FormatSignature(signature);
            BlobBuilder signatureBuilder = new BlobBuilder();
            if (!flags.HasFlag(SignRequestFlags.SSH_AGENT_OLD_SIGNATURE)) {
              signatureBuilder.AddStringBlob(algName);
            }
            signatureBuilder.AddBlob(signature);
            responseBuilder.AddBlob(signatureBuilder.GetBlob());
            responseBuilder.InsertHeader(Message.SSH2_AGENT_SIGN_RESPONSE);
            try {
              KeyUsed(this, new KeyUsedEventArgs(signKey, process));
            } catch { }
            break; // succeeded
              } catch (InvalidOperationException) {
            // this is expected if there is not a matching key
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failure

            case Message.SSH1_AGENTC_ADD_RSA_IDENTITY:
            case Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED:
              /*
               * Add to the list and return SSH_AGENT_SUCCESS, or
               * SSH_AGENT_FAILURE if the key was malformed.
               */

              if (IsLocked) {
            goto default;
              }

              bool ssh1constrained = (header.Message == Message.SSH1_AGENTC_ADD_RSA_ID_CONSTRAINED);

              try {
            var publicKeyParams = messageParser.ReadSsh1PublicKeyData(false);
            var keyPair = messageParser.ReadSsh1KeyData(publicKeyParams);

            SshKey key = new SshKey(SshVersion.SSH1, keyPair);
            key.Comment = messageParser.ReadString();
            key.Source = "External client";

            if (ssh1constrained) {
              while (messageStream.Position < header.BlobLength + 4) {
                KeyConstraint constraint = new KeyConstraint();
                constraint.Type = (KeyConstraintType)messageParser.ReadByte();
                if (constraint.Type ==
                  KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME) {
                  constraint.Data = messageParser.ReadInt();
                }
                key.AddConstraint(constraint);
              }
            }
            AddKey(key);
            responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
            break;

              } catch (CallbackNullException) {
            // this is expected
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }

              goto default; // failed

            case Message.SSH2_AGENTC_ADD_IDENTITY:
            case Message.SSH2_AGENTC_ADD_ID_CONSTRAINED:
              /*
               * Add to the list and return SSH_AGENT_SUCCESS, or
               * SSH_AGENT_FAILURE if the key was malformed.
               */

              if (IsLocked) {
            goto default;
              }

              bool constrained = (header.Message ==
              Message.SSH2_AGENTC_ADD_ID_CONSTRAINED);

              try {
            var publicKeyParams = messageParser.ReadSsh2PublicKeyData();
            var keyPair = messageParser.ReadSsh2KeyData(publicKeyParams);
            SshKey key = new SshKey(SshVersion.SSH2, keyPair);
            key.Comment = messageParser.ReadString();
            key.Source = "External client";

            if (constrained) {
              while (messageStream.Position < header.BlobLength + 4) {
                KeyConstraint constraint = new KeyConstraint();
                constraint.Type =
                  (KeyConstraintType)messageParser.ReadByte();
                if (constraint.Type ==
                  KeyConstraintType.SSH_AGENT_CONSTRAIN_LIFETIME) {
                  constraint.Data = messageParser.ReadInt();
                }
                key.AddConstraint(constraint);
              }
            }
            AddKey(key);
            responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
            break; // success!
              } catch (CallbackNullException) {
            // this is expected
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failed

            case Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY:
            case Message.SSH2_AGENTC_REMOVE_IDENTITY:
              /*
               * Remove from the list and return SSH_AGENT_SUCCESS, or
               * perhaps SSH_AGENT_FAILURE if it wasn't in the list to
               * start with.
               */

              if (IsLocked) {
            goto default;
              }

              SshVersion removeVersion;
              byte[] rKeyBlob;
              if (header.Message == Message.SSH1_AGENTC_REMOVE_RSA_IDENTITY) {
            removeVersion = SshVersion.SSH1;
            rKeyBlob = messageParser.ReadBytes(header.BlobLength - 1);
              } else if (header.Message == Message.SSH2_AGENTC_REMOVE_IDENTITY) {
            removeVersion = SshVersion.SSH2;
            rKeyBlob = messageParser.ReadBlob();
              } else {
            Debug.Fail("Should not get here.");
            goto default;
              }

              try {
            var matchingKey = mKeyList.Get(removeVersion, rKeyBlob);
            var startKeyListLength = mKeyList.Count;
            RemoveKey(matchingKey);
            // only succeed if key was removed
            if (mKeyList.Count == startKeyListLength - 1) {
              responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
              break; //success!
            }
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failed

            case Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
            case Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
              /*
               * Remove all SSH-1 or SSH-2 keys.
               */

              if (IsLocked) {
            goto default;
              }

              SshVersion removeAllVersion;
              if (header.Message == Message.SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES) {
            removeAllVersion = SshVersion.SSH1;
              } else if (header.Message == Message.SSH2_AGENTC_REMOVE_ALL_IDENTITIES) {
            removeAllVersion = SshVersion.SSH2;
              } else {
            Debug.Fail("Should not get here.");
            goto default;
              }

              try {
            RemoveAllKeys(removeAllVersion);
            responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
            break; //success!
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default; // failed

            case Message.SSH_AGENTC_LOCK:
              try {
            var passphrase = new PinnedArray<byte>(messageParser.ReadBlob());
            try {
              Lock(passphrase.Data);
            } finally {
              passphrase.Clear();
            }
            if (IsLocked) {
              responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
              break;
            }
              } catch (AgentLockedException) {
            // This is expected
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default;

            case Message.SSH_AGENTC_UNLOCK:
              try {
            var passphrase = new PinnedArray<byte>(messageParser.ReadBlob());
            try {
              Unlock(passphrase.Data);
            } finally {
              passphrase.Clear();
            }
            if (!IsLocked) {
              responseBuilder.InsertHeader(Message.SSH_AGENT_SUCCESS);
              break;
            }
              } catch (AgentLockedException) {
            // This is expected
              } catch (PassphraseException) {
            // This is expected
              } catch (Exception ex) {
            Debug.Fail(ex.ToString());
              }
              goto default;

            default:
              responseBuilder.Clear();
              responseBuilder.InsertHeader(Message.SSH_AGENT_FAILURE);
              break;
              }
              /* write response to stream */
              if (messageStream.CanSeek)
            messageStream.Position = 0;
              messageStream.Write(responseBuilder.GetBlob(), 0, responseBuilder.Length);
              messageStream.Flush();
        }
Example #8
0
        public ICollection <ISshKey> ListKeys(SshVersion aVersion)
        {
            BlobBuilder builder = new BlobBuilder();

            switch (aVersion)
            {
            case SshVersion.SSH1:
                builder.InsertHeader(Agent.Message.SSH1_AGENTC_REQUEST_RSA_IDENTITIES);
                break;

            case SshVersion.SSH2:
                builder.InsertHeader(Agent.Message.SSH2_AGENTC_REQUEST_IDENTITIES);
                break;

            default:
                throw new Exception(cUnsupportedSshVersion);
            }
            BlobParser replyParser   = SendMessage(builder);
            var        keyCollection = new List <ISshKey>();
            var        header        = replyParser.ReadHeader();

            switch (aVersion)
            {
            case SshVersion.SSH1:
                if (header.Message != Agent.Message.SSH1_AGENT_RSA_IDENTITIES_ANSWER)
                {
                    throw new AgentFailureException();
                }
                var ssh1KeyCount = replyParser.ReadUInt32();
                for (var i = 0; i < ssh1KeyCount; i++)
                {
                    var publicKeyParams = replyParser.ReadSsh1PublicKeyData(true);
                    var comment         = replyParser.ReadString();
                    keyCollection.Add(
                        new SshKey(SshVersion.SSH1, publicKeyParams, null, comment));
                }
                break;

            case SshVersion.SSH2:
                if (header.Message != Agent.Message.SSH2_AGENT_IDENTITIES_ANSWER)
                {
                    throw new AgentFailureException();
                }
                var ssh2KeyCount = replyParser.ReadUInt32();
                for (var i = 0; i < ssh2KeyCount; i++)
                {
                    var publicKeyBlob   = replyParser.ReadBlob();
                    var publicKeyParser = new BlobParser(publicKeyBlob);
                    OpensshCertificate cert;
                    var publicKeyParams = publicKeyParser.ReadSsh2PublicKeyData(out cert);
                    var comment         = replyParser.ReadString();
                    keyCollection.Add(
                        new SshKey(SshVersion.SSH2, publicKeyParams, null, comment, cert));
                }
                break;

            default:
                throw new Exception(cUnsupportedSshVersion);
            }
            return(keyCollection);
        }
Example #9
0
        private static AsymmetricCipherKeyPair CreateCipherKeyPair(
      PublicKeyAlgorithm algorithm,
      byte[] publicKeyBlob, byte[] privateKeyBlob)
        {
            var parser = new BlobParser(publicKeyBlob);
              var publicKey = parser.ReadSsh2PublicKeyData();
              parser = new BlobParser(privateKeyBlob);

              switch (algorithm) {
            case PublicKeyAlgorithm.SSH_RSA:
              var rsaPublicKeyParams = (RsaKeyParameters)publicKey;

              var d = new BigInteger(1, parser.ReadBlob());
              var p = new BigInteger(1, parser.ReadBlob());
              var q = new BigInteger(1, parser.ReadBlob());
              var inverseQ = new BigInteger(1, parser.ReadBlob());

              /* compute missing parameters */
              var dp = d.Remainder(p.Subtract(BigInteger.One));
              var dq = d.Remainder(q.Subtract(BigInteger.One));

              RsaPrivateCrtKeyParameters rsaPrivateKeyParams =
            new RsaPrivateCrtKeyParameters(rsaPublicKeyParams.Modulus,
              rsaPublicKeyParams.Exponent, d, p, q, dp, dq, inverseQ);

              return new AsymmetricCipherKeyPair(rsaPublicKeyParams,
            rsaPrivateKeyParams);

            case PublicKeyAlgorithm.SSH_DSS:
              var dsaPublicKeyParams = (DsaPublicKeyParameters)publicKey;

              var x = new BigInteger(1, parser.ReadBlob());
              DsaPrivateKeyParameters dsaPrivateKeyParams =
            new DsaPrivateKeyParameters(x, dsaPublicKeyParams.Parameters);

              return new AsymmetricCipherKeyPair(dsaPublicKeyParams,
            dsaPrivateKeyParams);
            case PublicKeyAlgorithm.ED25519:
              var ed25596PublicKey = (Ed25519PublicKeyParameter)publicKey;

              byte[] privBlob = parser.ReadBlob();
              byte[] privSig = new byte[64];
              // OpenSSH's "private key" is actually the private key with the public key tacked on ...
              Array.Copy(privBlob, 0, privSig, 0, 32);
              Array.Copy(ed25596PublicKey.Key, 0, privSig, 32, 32);
              var ed25596PrivateKey = new Ed25519PrivateKeyParameter(privSig);

              return new AsymmetricCipherKeyPair(ed25596PublicKey, ed25596PrivateKey);
            case PublicKeyAlgorithm.ECDSA_SHA2_NISTP256:
            case PublicKeyAlgorithm.ECDSA_SHA2_NISTP384:
            case PublicKeyAlgorithm.ECDSA_SHA2_NISTP521:
              var ecPublicKeyParams = (ECPublicKeyParameters)publicKey;

              var ecdsaPrivate = new BigInteger(1, parser.ReadBlob());
              ECPrivateKeyParameters ecPrivateKeyParams =
            new ECPrivateKeyParameters(ecdsaPrivate, ecPublicKeyParams.Parameters);

              return new AsymmetricCipherKeyPair(ecPublicKeyParams, ecPrivateKeyParams);
            default:
              // unsupported encryption algorithm
              throw new PpkFormatterException(PpkFormatterException.PpkErrorType.PublicKeyEncryption);
              }
        }
Example #10
0
 public ICollection<ISshKey> ListKeys(SshVersion aVersion)
 {
     BlobBuilder builder = new BlobBuilder();
       switch (aVersion) {
     case SshVersion.SSH1:
       builder.InsertHeader(Agent.Message.SSH1_AGENTC_REQUEST_RSA_IDENTITIES);
       break;
     case SshVersion.SSH2:
       builder.InsertHeader(Agent.Message.SSH2_AGENTC_REQUEST_IDENTITIES);
       break;
     default:
       throw new Exception(cUnsupportedSshVersion);
       }
       BlobParser replyParser = SendMessage(builder);
       var keyCollection = new List<ISshKey>();
       var header = replyParser.ReadHeader();
       switch (aVersion) {
     case SshVersion.SSH1:
       if (header.Message != Agent.Message.SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
     throw new AgentFailureException();
       }
       var ssh1KeyCount = replyParser.ReadInt();
       for (var i = 0; i < ssh1KeyCount; i++) {
     var publicKeyParams = replyParser.ReadSsh1PublicKeyData(true);
     var comment = replyParser.ReadString();
     keyCollection.Add(
       new SshKey(SshVersion.SSH1, publicKeyParams, null, comment));
       }
       break;
     case SshVersion.SSH2:
       if (header.Message != Agent.Message.SSH2_AGENT_IDENTITIES_ANSWER) {
     throw new AgentFailureException();
       }
       var ssh2KeyCount = replyParser.ReadInt();
       for (var i = 0; i < ssh2KeyCount; i++) {
     var publicKeyBlob = replyParser.ReadBlob();
     var publicKeyParser = new BlobParser(publicKeyBlob);
     var publicKeyParams = publicKeyParser.ReadSsh2PublicKeyData();
     var comment = replyParser.ReadString();
     keyCollection.Add(
       new SshKey(SshVersion.SSH2, publicKeyParams, null, comment));
       }
       break;
     default:
       throw new Exception(cUnsupportedSshVersion);
       }
       return keyCollection;
 }
Example #11
0
        private static AsymmetricCipherKeyPair CreateCipherKeyPair(
            PublicKeyAlgorithm algorithm,
            byte[] publicKeyBlob, byte[] privateKeyBlob)
        {
            var parser = new BlobParser(publicKeyBlob);
            OpensshCertificate cert;
            var publicKey = parser.ReadSsh2PublicKeyData(out cert);

            parser = new BlobParser(privateKeyBlob);

            switch (algorithm)
            {
            case PublicKeyAlgorithm.SSH_RSA:
                var rsaPublicKeyParams = (RsaKeyParameters)publicKey;

                var d        = new BigInteger(1, parser.ReadBlob());
                var p        = new BigInteger(1, parser.ReadBlob());
                var q        = new BigInteger(1, parser.ReadBlob());
                var inverseQ = new BigInteger(1, parser.ReadBlob());

                /* compute missing parameters */
                var dp = d.Remainder(p.Subtract(BigInteger.One));
                var dq = d.Remainder(q.Subtract(BigInteger.One));

                RsaPrivateCrtKeyParameters rsaPrivateKeyParams =
                    new RsaPrivateCrtKeyParameters(rsaPublicKeyParams.Modulus,
                                                   rsaPublicKeyParams.Exponent, d, p, q, dp, dq, inverseQ);

                return(new AsymmetricCipherKeyPair(rsaPublicKeyParams,
                                                   rsaPrivateKeyParams));

            case PublicKeyAlgorithm.SSH_DSS:
                var dsaPublicKeyParams = (DsaPublicKeyParameters)publicKey;

                var x = new BigInteger(1, parser.ReadBlob());
                DsaPrivateKeyParameters dsaPrivateKeyParams =
                    new DsaPrivateKeyParameters(x, dsaPublicKeyParams.Parameters);

                return(new AsymmetricCipherKeyPair(dsaPublicKeyParams,
                                                   dsaPrivateKeyParams));

            case PublicKeyAlgorithm.ED25519:
                var ed25596PublicKey = (Ed25519PublicKeyParameter)publicKey;

                byte[] privBlob = parser.ReadBlob();
                byte[] privSig  = new byte[64];
                // OpenSSH's "private key" is actually the private key with the public key tacked on ...
                Array.Copy(privBlob, 0, privSig, 0, 32);
                Array.Copy(ed25596PublicKey.Key, 0, privSig, 32, 32);
                var ed25596PrivateKey = new Ed25519PrivateKeyParameter(privSig);

                return(new AsymmetricCipherKeyPair(ed25596PublicKey, ed25596PrivateKey));

            case PublicKeyAlgorithm.ECDSA_SHA2_NISTP256:
            case PublicKeyAlgorithm.ECDSA_SHA2_NISTP384:
            case PublicKeyAlgorithm.ECDSA_SHA2_NISTP521:
                var ecPublicKeyParams = (ECPublicKeyParameters)publicKey;

                var ecdsaPrivate = new BigInteger(1, parser.ReadBlob());
                ECPrivateKeyParameters ecPrivateKeyParams =
                    new ECPrivateKeyParameters(ecdsaPrivate, ecPublicKeyParams.Parameters);

                return(new AsymmetricCipherKeyPair(ecPublicKeyParams, ecPrivateKeyParams));

            default:
                // unsupported encryption algorithm
                throw new PpkFormatterException(PpkFormatterException.PpkErrorType.PublicKeyEncryption);
            }
        }