public void TestIncompleteIntegerTag() { using (MemoryStream mem = new MemoryStream( new byte[] { 0x02, 0x04, 0x12, 0x34, 0x56 } )) { BERReader reader = new BERReader(mem); BigInteger n; Assert.False(reader.ReadInteger(out n)); } }
public void TestNonIntegerTag() { using (MemoryStream mem = new MemoryStream( new byte[] { 0x30, 0x03, 0x02, 0x01, 0x01 } )) { BERReader reader = new BERReader(mem); BigInteger n; Assert.False(reader.ReadInteger(out n)); } }
public void TestIncompleteTag() { using (MemoryStream mem = new MemoryStream( new byte[] { 0x7f, 0x87, 0xef, 0xab, 0xb7, 0x6e } )) { BERReader reader = new BERReader(mem); BERReader.BERTagInfo tagInfo = new BERReader.BERTagInfo(); Assert.False(reader.ReadTagInfo(ref tagInfo)); } }
public void TestIntegerTag4() { using (MemoryStream mem = new MemoryStream( new byte[] { 0x02, 0x09, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x01 } )) { BERReader reader = new BERReader(mem); BigInteger n; Assert.True(reader.ReadInteger(out n)); Assert.AreEqual("123456789ABCDEF001", n.ToString(16)); } }
public void TestIntegerTag3() { using (MemoryStream mem = new MemoryStream( new byte[] { 0x02, 0x01, 0x00 } )) { BERReader reader = new BERReader(mem); BigInteger n; Assert.True(reader.ReadInteger(out n)); Assert.AreEqual("0", n.ToString()); } }
public void TestLargeTag() { using (MemoryStream mem = new MemoryStream( new byte[] { 0x7f, 0x87, 0xef, 0xab, 0xb7, 0x6e, 0x03, 0x02, 0x01, 0x01 } )) { BERReader reader = new BERReader(mem); BERReader.BERTagInfo tagInfo = new BERReader.BERTagInfo(); Assert.True(reader.ReadTagInfo(ref tagInfo)); Assert.AreEqual(1, tagInfo.ClassBits); Assert.AreEqual(true, tagInfo.IsConstructed); Assert.AreEqual(0x7deadbee, tagInfo.TagNumber); Assert.AreEqual(3, tagInfo.Length); } }
/// <summary> /// Read 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) { PEMKeyType keyType; String base64Text; bool encrypted = false; CipherAlgorithm?encryption = null; byte[] iv = null; int keySize = 0; int ivSize = 0; using (StreamReader sreader = GetStreamReader()) { string line = sreader.ReadLine(); if (line == null) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)"); } if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_RSA) { keyType = PEMKeyType.RSA; } else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_DSA) { keyType = PEMKeyType.DSA; } else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_ECDSA) { keyType = PEMKeyType.ECDSA; } else { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected key type)"); } string footer = line.Replace("BEGIN", "END"); StringBuilder buf = new StringBuilder(); comment = String.Empty; while (true) { line = sreader.ReadLine(); if (line == null) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)"); } if (line == footer) { break; } if (line.IndexOf(':') >= 0) { if (line.StartsWith("Proc-Type:")) { string[] w = line.Substring("Proc-Type:".Length).Trim().Split(','); if (w.Length < 1) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid Proc-Type)"); } if (w[0] != "4") { throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat") + " (" + Strings.GetString("Reason_UnsupportedProcType") + ")"); } if (w.Length >= 2 && w[1] == "ENCRYPTED") { encrypted = true; } } else if (line.StartsWith("DEK-Info:")) { string[] w = line.Substring("DEK-Info:".Length).Trim().Split(','); if (w.Length < 2) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid DEK-Info)"); } switch (w[0]) { case "DES-EDE3-CBC": encryption = CipherAlgorithm.TripleDES; ivSize = 8; keySize = 24; break; case "AES-128-CBC": encryption = CipherAlgorithm.AES128; ivSize = 16; keySize = 16; break; default: throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat") + " (" + Strings.GetString("Reason_UnsupportedEncryptionType") + ")"); } iv = HexToByteArray(w[1]); if (iv == null || iv.Length != ivSize) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid IV)"); } } } else { buf.Append(line); } } base64Text = buf.ToString(); } byte[] keydata = Base64.Decode(Encoding.ASCII.GetBytes(base64Text)); if (encrypted) { if (!encryption.HasValue || iv == null) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing encryption type or IV)"); } byte[] key = PassphraseToKey(passphrase, iv, keySize); Cipher cipher = CipherFactory.CreateCipher(SSHProtocol.SSH2, encryption.Value, key, iv); if (keydata.Length % cipher.BlockSize != 0) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid key data size)"); } cipher.Decrypt(keydata, 0, keydata.Length, keydata, 0); } using (MemoryStream keyDataStream = new MemoryStream(keydata, false)) { BERReader reader = new BERReader(keyDataStream); if (!reader.ReadSequence()) { throw new SSHException(Strings.GetString("WrongPassphrase")); } if (keyType == PEMKeyType.RSA) { /* from OpenSSL rsa_asn1.c * * ASN1_SIMPLE(RSA, version, LONG), * ASN1_SIMPLE(RSA, n, BIGNUM), * ASN1_SIMPLE(RSA, e, BIGNUM), * ASN1_SIMPLE(RSA, d, BIGNUM), * ASN1_SIMPLE(RSA, p, BIGNUM), * ASN1_SIMPLE(RSA, q, BIGNUM), * ASN1_SIMPLE(RSA, dmp1, BIGNUM), * ASN1_SIMPLE(RSA, dmq1, BIGNUM), * ASN1_SIMPLE(RSA, iqmp, BIGNUM) */ BigInteger v, n, e, d, p, q, dmp1, dmq1, iqmp; if (!reader.ReadInteger(out v) || !reader.ReadInteger(out n) || !reader.ReadInteger(out e) || !reader.ReadInteger(out d) || !reader.ReadInteger(out p) || !reader.ReadInteger(out q) || !reader.ReadInteger(out dmp1) || !reader.ReadInteger(out dmq1) || !reader.ReadInteger(out iqmp)) { throw new SSHException(Strings.GetString("WrongPassphrase")); } BigInteger u = p.ModInverse(q); // inverse of p mod q keyPair = new RSAKeyPair(e, d, n, u, p, q); } else if (keyType == PEMKeyType.DSA) { /* from OpenSSL dsa_asn1.c * * ASN1_SIMPLE(DSA, version, LONG), * ASN1_SIMPLE(DSA, p, BIGNUM), * ASN1_SIMPLE(DSA, q, BIGNUM), * ASN1_SIMPLE(DSA, g, BIGNUM), * ASN1_SIMPLE(DSA, pub_key, BIGNUM), * ASN1_SIMPLE(DSA, priv_key, BIGNUM) */ BigInteger v, p, q, g, y, x; if (!reader.ReadInteger(out v) || !reader.ReadInteger(out p) || !reader.ReadInteger(out q) || !reader.ReadInteger(out g) || !reader.ReadInteger(out y) || !reader.ReadInteger(out x)) { throw new SSHException(Strings.GetString("WrongPassphrase")); } keyPair = new DSAKeyPair(p, g, q, y, x); } else if (keyType == PEMKeyType.ECDSA) { /* from OpenSSL ec_asn1.c * * ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG), * ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING), * ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0), * ------ * ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT), * ------ * ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1) */ int len; byte[] privateKey; byte[] publicKey; string namedCurve; BigInteger v; if (!reader.ReadInteger(out v) || !reader.ReadOctetString(out privateKey) || !reader.ReadTag(BERReader.TagClass.ContextSpecific, true, 0, out len) || !reader.ReadObjectIdentifier(out namedCurve) || !reader.ReadTag(BERReader.TagClass.ContextSpecific, true, 1, out len) || !reader.ReadBitString(out publicKey)) { throw new SSHException(Strings.GetString("WrongPassphrase")); } EllipticCurve curve = EllipticCurve.FindByOID(namedCurve); if (curve == null) { throw new SSHException(Strings.GetString("UnsupportedEllipticCurveInKeyPair")); } ECPoint ecPublicKeyPoint; if (!ECPoint.Parse(publicKey, curve, out ecPublicKeyPoint)) { throw new SSHException(Strings.GetString("KeysAreBroken")); } var ecKeyPair = new ECDSAKeyPair(curve, new ECDSAPublicKey(curve, ecPublicKeyPoint), new BigInteger(privateKey)); if (!ecKeyPair.CheckKeyConsistency()) { throw new SSHException(Strings.GetString("KeysAreBroken")); } keyPair = ecKeyPair; } else { throw new SSHException("Unknown file type. This should not happen."); } } }
/// <summary> /// Read 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) { PEMKeyType keyType; String base64Text; bool encrypted = false; CipherAlgorithm? encryption = null; byte[] iv = null; int keySize = 0; int ivSize = 0; using (StreamReader sreader = GetStreamReader()) { string line = sreader.ReadLine(); if (line == null) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)"); if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_RSA) keyType = PEMKeyType.RSA; else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_DSA) keyType = PEMKeyType.DSA; else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_ECDSA) keyType = PEMKeyType.ECDSA; else throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected key type)"); string footer = line.Replace("BEGIN", "END"); StringBuilder buf = new StringBuilder(); comment = String.Empty; while (true) { line = sreader.ReadLine(); if (line == null) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)"); if (line == footer) break; if (line.IndexOf(':') >= 0) { if (line.StartsWith("Proc-Type:")) { string[] w = line.Substring("Proc-Type:".Length).Trim().Split(','); if (w.Length < 1) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid Proc-Type)"); if (w[0] != "4") throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat") + " (" + Strings.GetString("Reason_UnsupportedProcType") + ")"); if (w.Length >= 2 && w[1] == "ENCRYPTED") encrypted = true; } else if (line.StartsWith("DEK-Info:")) { string[] w = line.Substring("DEK-Info:".Length).Trim().Split(','); if (w.Length < 2) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid DEK-Info)"); switch (w[0]) { case "DES-EDE3-CBC": encryption = CipherAlgorithm.TripleDES; ivSize = 8; keySize = 24; break; case "AES-128-CBC": encryption = CipherAlgorithm.AES128; ivSize = 16; keySize = 16; break; default: throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat") + " (" + Strings.GetString("Reason_UnsupportedEncryptionType") + ")"); } iv = HexToByteArray(w[1]); if (iv == null || iv.Length != ivSize) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid IV)"); } } else buf.Append(line); } base64Text = buf.ToString(); } byte[] keydata = Base64.Decode(Encoding.ASCII.GetBytes(base64Text)); if (encrypted) { if (!encryption.HasValue || iv == null) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing encryption type or IV)"); byte[] key = PassphraseToKey(passphrase, iv, keySize); Cipher cipher = CipherFactory.CreateCipher(SSHProtocol.SSH2, encryption.Value, key, iv); if (keydata.Length % cipher.BlockSize != 0) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid key data size)"); cipher.Decrypt(keydata, 0, keydata.Length, keydata, 0); } using (MemoryStream keyDataStream = new MemoryStream(keydata, false)) { BERReader reader = new BERReader(keyDataStream); if (!reader.ReadSequence()) throw new SSHException(Strings.GetString("WrongPassphrase")); if (keyType == PEMKeyType.RSA) { /* from OpenSSL rsa_asn1.c * * ASN1_SIMPLE(RSA, version, LONG), * ASN1_SIMPLE(RSA, n, BIGNUM), * ASN1_SIMPLE(RSA, e, BIGNUM), * ASN1_SIMPLE(RSA, d, BIGNUM), * ASN1_SIMPLE(RSA, p, BIGNUM), * ASN1_SIMPLE(RSA, q, BIGNUM), * ASN1_SIMPLE(RSA, dmp1, BIGNUM), * ASN1_SIMPLE(RSA, dmq1, BIGNUM), * ASN1_SIMPLE(RSA, iqmp, BIGNUM) */ BigInteger v, n, e, d, p, q, dmp1, dmq1, iqmp; if (!reader.ReadInteger(out v) || !reader.ReadInteger(out n) || !reader.ReadInteger(out e) || !reader.ReadInteger(out d) || !reader.ReadInteger(out p) || !reader.ReadInteger(out q) || !reader.ReadInteger(out dmp1) || !reader.ReadInteger(out dmq1) || !reader.ReadInteger(out iqmp)) { throw new SSHException(Strings.GetString("WrongPassphrase")); } BigInteger u = p.ModInverse(q); // inverse of p mod q keyPair = new RSAKeyPair(e, d, n, u, p, q); } else if (keyType == PEMKeyType.DSA) { /* from OpenSSL dsa_asn1.c * * ASN1_SIMPLE(DSA, version, LONG), * ASN1_SIMPLE(DSA, p, BIGNUM), * ASN1_SIMPLE(DSA, q, BIGNUM), * ASN1_SIMPLE(DSA, g, BIGNUM), * ASN1_SIMPLE(DSA, pub_key, BIGNUM), * ASN1_SIMPLE(DSA, priv_key, BIGNUM) */ BigInteger v, p, q, g, y, x; if (!reader.ReadInteger(out v) || !reader.ReadInteger(out p) || !reader.ReadInteger(out q) || !reader.ReadInteger(out g) || !reader.ReadInteger(out y) || !reader.ReadInteger(out x)) { throw new SSHException(Strings.GetString("WrongPassphrase")); } keyPair = new DSAKeyPair(p, g, q, y, x); } else if (keyType == PEMKeyType.ECDSA) { /* from OpenSSL ec_asn1.c * * ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG), * ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING), * ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0), * ------ * ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT), * ------ * ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1) */ int len; byte[] privateKey; byte[] publicKey; string namedCurve; BigInteger v; if (!reader.ReadInteger(out v) || !reader.ReadOctetString(out privateKey) || !reader.ReadTag(BERReader.TagClass.ContextSpecific, true, 0, out len) || !reader.ReadObjectIdentifier(out namedCurve) || !reader.ReadTag(BERReader.TagClass.ContextSpecific, true, 1, out len) || !reader.ReadBitString(out publicKey)) { throw new SSHException(Strings.GetString("WrongPassphrase")); } EllipticCurve curve = EllipticCurve.FindByOID(namedCurve); if (curve == null) { throw new SSHException(Strings.GetString("UnsupportedEllipticCurveInKeyPair")); } ECPoint ecPublicKeyPoint; if (!ECPoint.Parse(publicKey, curve, out ecPublicKeyPoint)) { throw new SSHException(Strings.GetString("KeysAreBroken")); } var ecKeyPair = new ECDSAKeyPair(curve, new ECDSAPublicKey(curve, ecPublicKeyPoint), new BigInteger(privateKey)); if (!ecKeyPair.CheckKeyConsistency()) { throw new SSHException(Strings.GetString("KeysAreBroken")); } keyPair = ecKeyPair; } else { throw new SSHException("Unknown file type. This should not happen."); } } }
public void TestNonSequenceTag() { using (MemoryStream mem = new MemoryStream( new byte[] { 0x02, 0x01, 0x01 } )) { BERReader reader = new BERReader(mem); Assert.False(reader.ReadSequence()); } }
public void TestSequenceTag1() { using (MemoryStream mem = new MemoryStream( new byte[] { 0x30, 0x03, 0x02, 0x01, 0x01 } )) { BERReader reader = new BERReader(mem); Assert.True(reader.ReadSequence()); } }
/// <summary> /// Read OpenSSH 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"); } KeyType keyType; String base64Text; bool encrypted = false; CipherAlgorithm?encryption = null; byte[] iv = null; int keySize = 0; int ivSize = 0; using (StreamReader sreader = GetStreamReader()) { string line = sreader.ReadLine(); if (line == null) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)"); } if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_RSA) { keyType = KeyType.RSA; } else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_DSA) { keyType = KeyType.DSA; } else { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected key type)"); } string footer = line.Replace("BEGIN", "END"); StringBuilder buf = new StringBuilder(); comment = String.Empty; while (true) { line = sreader.ReadLine(); if (line == null) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)"); } if (line == footer) { break; } if (line.IndexOf(':') >= 0) { if (line.StartsWith("Proc-Type:")) { string[] w = line.Substring("Proc-Type:".Length).Trim().Split(','); if (w.Length < 1) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid Proc-Type)"); } if (w[0] != "4") { throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat") + " (" + Strings.GetString("Reason_UnsupportedProcType") + ")"); } if (w.Length >= 2 && w[1] == "ENCRYPTED") { encrypted = true; } } else if (line.StartsWith("DEK-Info:")) { string[] w = line.Substring("DEK-Info:".Length).Trim().Split(','); if (w.Length < 2) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid DEK-Info)"); } switch (w[0]) { case "DES-EDE3-CBC": encryption = CipherAlgorithm.TripleDES; ivSize = 8; keySize = 24; break; case "AES-128-CBC": encryption = CipherAlgorithm.AES128; ivSize = 16; keySize = 16; break; default: throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat") + " (" + Strings.GetString("Reason_UnsupportedEncryptionType") + ")"); } iv = HexToByteArray(w[1]); if (iv == null || iv.Length != ivSize) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid IV)"); } } } else { buf.Append(line); } } base64Text = buf.ToString(); } byte[] keydata = Base64.Decode(Encoding.ASCII.GetBytes(base64Text)); if (encrypted) { if (!encryption.HasValue || iv == null) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing encryption type or IV)"); } byte[] key = OpenSSHPassphraseToKey(passphrase, iv, keySize); Cipher cipher = CipherFactory.CreateCipher(SSHProtocol.SSH2, encryption.Value, key, iv); if (keydata.Length % cipher.BlockSize != 0) { throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid key data size)"); } cipher.Decrypt(keydata, 0, keydata.Length, keydata, 0); } using (MemoryStream keyDataStream = new MemoryStream(keydata, false)) { BERReader reader = new BERReader(keyDataStream); if (!reader.ReadSequence()) { throw new SSHException(Strings.GetString("WrongPassphrase")); } if (keyType == KeyType.RSA) { /* from OpenSSL rsa_asn1.c * * ASN1_SIMPLE(RSA, version, LONG), * ASN1_SIMPLE(RSA, n, BIGNUM), * ASN1_SIMPLE(RSA, e, BIGNUM), * ASN1_SIMPLE(RSA, d, BIGNUM), * ASN1_SIMPLE(RSA, p, BIGNUM), * ASN1_SIMPLE(RSA, q, BIGNUM), * ASN1_SIMPLE(RSA, dmp1, BIGNUM), * ASN1_SIMPLE(RSA, dmq1, BIGNUM), * ASN1_SIMPLE(RSA, iqmp, BIGNUM) */ BigInteger v, n, e, d, p, q, dmp1, dmq1, iqmp; if (!reader.ReadInteger(out v) || !reader.ReadInteger(out n) || !reader.ReadInteger(out e) || !reader.ReadInteger(out d) || !reader.ReadInteger(out p) || !reader.ReadInteger(out q) || !reader.ReadInteger(out dmp1) || !reader.ReadInteger(out dmq1) || !reader.ReadInteger(out iqmp)) { throw new SSHException(Strings.GetString("WrongPassphrase")); } BigInteger u = p.modInverse(q); // inverse of p mod q keyPair = new RSAKeyPair(e, d, n, u, p, q); } else if (keyType == KeyType.DSA) { /* from OpenSSL dsa_asn1.c * * ASN1_SIMPLE(DSA, version, LONG), * ASN1_SIMPLE(DSA, p, BIGNUM), * ASN1_SIMPLE(DSA, q, BIGNUM), * ASN1_SIMPLE(DSA, g, BIGNUM), * ASN1_SIMPLE(DSA, pub_key, BIGNUM), * ASN1_SIMPLE(DSA, priv_key, BIGNUM) */ BigInteger v, p, q, g, y, x; if (!reader.ReadInteger(out v) || !reader.ReadInteger(out p) || !reader.ReadInteger(out q) || !reader.ReadInteger(out g) || !reader.ReadInteger(out y) || !reader.ReadInteger(out x)) { throw new SSHException(Strings.GetString("WrongPassphrase")); } keyPair = new DSAKeyPair(p, g, q, y, x); } else { throw new SSHException("Unknown file type. This should not happen."); } } }
public void TestIndefiniteSequenceTag() { using (MemoryStream mem = new MemoryStream( new byte[] { 0x30, 0x80, 0x02, 0x01, 0x01, 0x00, 0x00 } )) { BERReader reader = new BERReader(mem); Assert.True(reader.ReadSequence()); } }
public void TestIncompleteSequenceTag() { using (MemoryStream mem = new MemoryStream( new byte[] { 0x30 } )) { BERReader reader = new BERReader(mem); Assert.False(reader.ReadSequence()); } }
/// <summary> /// Read OpenSSH 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"); KeyType keyType; String base64Text; bool encrypted = false; CipherAlgorithm? encryption = null; byte[] iv = null; int keySize = 0; int ivSize = 0; using (StreamReader sreader = GetStreamReader()) { string line = sreader.ReadLine(); if (line == null) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)"); if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_RSA) keyType = KeyType.RSA; else if (line == PrivateKeyFileHeader.SSH2_OPENSSH_HEADER_DSA) keyType = KeyType.DSA; else throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected key type)"); string footer = line.Replace("BEGIN", "END"); StringBuilder buf = new StringBuilder(); comment = String.Empty; while (true) { line = sreader.ReadLine(); if (line == null) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (unexpected eof)"); if (line == footer) break; if (line.IndexOf(':') >= 0) { if (line.StartsWith("Proc-Type:")) { string[] w = line.Substring("Proc-Type:".Length).Trim().Split(','); if (w.Length < 1) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid Proc-Type)"); if (w[0] != "4") throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat") + " (" + Strings.GetString("Reason_UnsupportedProcType") + ")"); if (w.Length >= 2 && w[1] == "ENCRYPTED") encrypted = true; } else if (line.StartsWith("DEK-Info:")) { string[] w = line.Substring("DEK-Info:".Length).Trim().Split(','); if (w.Length < 2) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid DEK-Info)"); switch (w[0]) { case "DES-EDE3-CBC": encryption = CipherAlgorithm.TripleDES; ivSize = 8; keySize = 24; break; case "AES-128-CBC": encryption = CipherAlgorithm.AES128; ivSize = 16; keySize = 16; break; default: throw new SSHException(Strings.GetString("UnsupportedPrivateKeyFormat") + " (" + Strings.GetString("Reason_UnsupportedEncryptionType") + ")"); } iv = HexToByteArray(w[1]); if (iv == null || iv.Length != ivSize) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid IV)"); } } else buf.Append(line); } base64Text = buf.ToString(); } byte[] keydata = Base64.Decode(Encoding.ASCII.GetBytes(base64Text)); if (encrypted) { if (!encryption.HasValue || iv == null) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (missing encryption type or IV)"); byte[] key = OpenSSHPassphraseToKey(passphrase, iv, keySize); Cipher cipher = CipherFactory.CreateCipher(SSHProtocol.SSH2, encryption.Value, key, iv); if (keydata.Length % cipher.BlockSize != 0) throw new SSHException(Strings.GetString("NotValidPrivateKeyFile") + " (invalid key data size)"); cipher.Decrypt(keydata, 0, keydata.Length, keydata, 0); } using (MemoryStream keyDataStream = new MemoryStream(keydata, false)) { BERReader reader = new BERReader(keyDataStream); if (!reader.ReadSequence()) throw new SSHException(Strings.GetString("WrongPassphrase")); if (keyType == KeyType.RSA) { /* from OpenSSL rsa_asn1.c * * ASN1_SIMPLE(RSA, version, LONG), * ASN1_SIMPLE(RSA, n, BIGNUM), * ASN1_SIMPLE(RSA, e, BIGNUM), * ASN1_SIMPLE(RSA, d, BIGNUM), * ASN1_SIMPLE(RSA, p, BIGNUM), * ASN1_SIMPLE(RSA, q, BIGNUM), * ASN1_SIMPLE(RSA, dmp1, BIGNUM), * ASN1_SIMPLE(RSA, dmq1, BIGNUM), * ASN1_SIMPLE(RSA, iqmp, BIGNUM) */ BigInteger v, n, e, d, p, q, dmp1, dmq1, iqmp; if (!reader.ReadInteger(out v) || !reader.ReadInteger(out n) || !reader.ReadInteger(out e) || !reader.ReadInteger(out d) || !reader.ReadInteger(out p) || !reader.ReadInteger(out q) || !reader.ReadInteger(out dmp1) || !reader.ReadInteger(out dmq1) || !reader.ReadInteger(out iqmp)) { throw new SSHException(Strings.GetString("WrongPassphrase")); } BigInteger u = p.modInverse(q); // inverse of p mod q keyPair = new RSAKeyPair(e, d, n, u, p, q); } else if (keyType == KeyType.DSA) { /* from OpenSSL dsa_asn1.c * * ASN1_SIMPLE(DSA, version, LONG), * ASN1_SIMPLE(DSA, p, BIGNUM), * ASN1_SIMPLE(DSA, q, BIGNUM), * ASN1_SIMPLE(DSA, g, BIGNUM), * ASN1_SIMPLE(DSA, pub_key, BIGNUM), * ASN1_SIMPLE(DSA, priv_key, BIGNUM) */ BigInteger v, p, q, g, y, x; if (!reader.ReadInteger(out v) || !reader.ReadInteger(out p) || !reader.ReadInteger(out q) || !reader.ReadInteger(out g) || !reader.ReadInteger(out y) || !reader.ReadInteger(out x)) { throw new SSHException(Strings.GetString("WrongPassphrase")); } keyPair = new DSAKeyPair(p, g, q, y, x); } else { throw new SSHException("Unknown file type. This should not happen."); } } }