internal static EDDSAPublicKey ReadFrom(PublicKeyAlgorithm algorithm, SSH2DataReader reader) { EdwardsCurve curve = EdwardsCurve.FindByAlgorithm(algorithm); if (curve == null) { throw new SSHException(Strings.GetString("UnsupportedEllipticCurve")); } byte[] q = reader.ReadByteString(); return(new EDDSAPublicKey(curve, q)); }
/// <summary> /// Read PuTTY SSH2 private key parameters. /// </summary> /// <param name="passphrase">passphrase for decrypt the key file</param> /// <param name="keyPair">key pair</param> /// <param name="comment">comment or empty if it didn't exist</param> public void Load(string passphrase, out KeyPair keyPair, out string comment) { if (keyFile == null) { throw new SSHException("A key file is not loaded yet"); } int version; string keyTypeName; KeyType keyType; string encryptionName; CipherAlgorithm?encryption; byte[] publicBlob; byte[] privateBlob; string privateMac; string privateHash; using (StreamReader sreader = GetStreamReader()) { //*** Read header and key type ReadHeaderLine(sreader, out version, out keyTypeName); if (keyTypeName == "ssh-rsa") { keyType = KeyType.RSA; } else if (keyTypeName == "ssh-dss") { keyType = KeyType.DSA; } else if (keyTypeName.StartsWith("ecdsa-sha2-")) { keyType = KeyType.ECDSA; } else if (keyTypeName == "ssh-ed25519") { keyType = KeyType.ED25519; } else { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected key type)"); } //*** Read encryption ReadItemLine(sreader, "Encryption", out encryptionName); if (encryptionName == "aes256-cbc") { encryption = CipherAlgorithm.AES256; } else if (encryptionName == "none") { encryption = null; passphrase = ""; // prevent HMAC error } else { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected encryption)"); } //*** Read comment ReadItemLine(sreader, "Comment", out comment); //*** Read public lines string publicLinesStr; ReadItemLine(sreader, "Public-Lines", out publicLinesStr); int publicLines; if (!Int32.TryParse(publicLinesStr, out publicLines) || publicLines < 0) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid public lines)"); } ReadBlob(sreader, publicLines, out publicBlob); //*** Read private lines string privateLinesStr; ReadItemLine(sreader, "Private-Lines", out privateLinesStr); int privateLines; if (!Int32.TryParse(privateLinesStr, out privateLines) || privateLines < 0) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid private lines)"); } ReadBlob(sreader, privateLines, out privateBlob); //*** Read private MAC ReadPrivateMACLine(sreader, version, out privateMac, out privateHash); } if (encryption.HasValue) { byte[] key = PuTTYPassphraseToKey(passphrase); byte[] iv = new byte[16]; Cipher cipher = CipherFactory.CreateCipher(SSHProtocol.SSH2, encryption.Value, key, iv); if (privateBlob.Length % cipher.BlockSize != 0) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid key data size)"); } cipher.Decrypt(privateBlob, 0, privateBlob.Length, privateBlob, 0); } bool verified = Verify(version, privateMac, privateHash, passphrase, keyTypeName, encryptionName, comment, publicBlob, privateBlob); if (!verified) { if (encryption.HasValue) { throw new SSHException(Strings.GetString("WrongPassphrase")); } else { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (HMAC verification failed)"); } } if (keyType == KeyType.RSA) { SSH2DataReader reader = new SSH2DataReader(publicBlob); string magic = reader.ReadString(); if (magic != "ssh-rsa") { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing magic)"); } BigInteger e = reader.ReadMPInt(); BigInteger n = reader.ReadMPInt(); reader = new SSH2DataReader(privateBlob); BigInteger d = reader.ReadMPInt(); BigInteger p = reader.ReadMPInt(); BigInteger q = reader.ReadMPInt(); BigInteger iqmp = reader.ReadMPInt(); BigInteger u = p.ModInverse(q); keyPair = new RSAKeyPair(e, d, n, u, p, q); } else if (keyType == KeyType.DSA) { SSH2DataReader reader = new SSH2DataReader(publicBlob); string magic = reader.ReadString(); if (magic != "ssh-dss") { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing magic)"); } BigInteger p = reader.ReadMPInt(); BigInteger q = reader.ReadMPInt(); BigInteger g = reader.ReadMPInt(); BigInteger y = reader.ReadMPInt(); reader = new SSH2DataReader(privateBlob); BigInteger x = reader.ReadMPInt(); keyPair = new DSAKeyPair(p, g, q, y, x); } else if (keyType == KeyType.ECDSA) { SSH2DataReader reader = new SSH2DataReader(publicBlob); string algorithmName = reader.ReadString(); string curveName = reader.ReadString(); byte[] publicKeyPt = reader.ReadByteString(); reader = new SSH2DataReader(privateBlob); BigInteger privateKey = reader.ReadMPInt(); EllipticCurve curve = EllipticCurve.FindByName(curveName); if (curve == null) { throw new SSHException(Strings.GetString("UnsupportedEllipticCurve") + " : " + curveName); } ECPoint publicKey; if (!ECPoint.Parse(publicKeyPt, curve, out publicKey)) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (parsing public key failed)"); } keyPair = new ECDSAKeyPair(curve, new ECDSAPublicKey(curve, publicKey), privateKey); if (!((ECDSAKeyPair)keyPair).CheckKeyConsistency()) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid key pair)"); } } else if (keyType == KeyType.ED25519) { SSH2DataReader reader = new SSH2DataReader(publicBlob); string algorithmName = reader.ReadString(); byte[] publicKey = reader.ReadByteString(); reader = new SSH2DataReader(privateBlob); byte[] privateKey = reader.ReadByteString(); EdwardsCurve curve = EdwardsCurve.FindByAlgorithm(PublicKeyAlgorithm.ED25519); if (curve == null) { throw new SSHException(Strings.GetString("UnsupportedEllipticCurve")); } keyPair = new EDDSAKeyPair(curve, new EDDSAPublicKey(curve, publicKey), privateKey); if (!((EDDSAKeyPair)keyPair).CheckKeyConsistency()) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid key pair)"); } } else { throw new SSHException("Unknown file type. This should not happen."); } }