/SharpSSH/jsch/KeyPair.cs
C# | 803 lines | 671 code | 86 blank | 46 comment | 199 complexity | 139187b536964b4df6c4928c9518f5a4 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
- using System;
- using System.IO;
- using System.Runtime.CompilerServices;
-
- using SharpSsh.Jsch;
- using SharpSsh;
-
- namespace SharpSsh.jsch
- {
- /*
- Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the distribution.
-
- 3. The names of the authors may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
- INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- public abstract class KeyPair
- {
- public const int ERROR = 0;
- public const int DSA = 1;
- public const int RSA = 2;
- public const int UNKNOWN = 3;
-
- internal const int VENDOR_OPENSSH = 0;
- internal const int VENDOR_FSECURE = 1;
- internal int vendor = VENDOR_OPENSSH;
-
- private static byte[] m_cr = Util.GetBytes("\n");
- private static byte[] m_space = Util.GetBytes(" ");
-
- private bool m_encrypted = false;
- private byte[] m_data = null;
- private byte[] m_iv = null;
- private byte[] m_publickeyblob = null;
-
- internal JSch m_jsch = null;
- private Cipher m_cipher;
- private HashAlgorithm m_hash;
- private IRandom m_random;
-
- private byte[] m_passphrase;
-
- static byte[][] m_header ={Util.GetBytes( "Proc-Type: 4,ENCRYPTED"),
- Util.GetBytes("DEK-Info: DES-EDE3-CBC,")};
-
- public static KeyPair GenKeyPair(JSch jsch, int type)
- {
- return GenKeyPair(jsch, type, 1024);
- }
-
- public static KeyPair GenKeyPair(JSch jsch, int type, int key_size)
- {
- KeyPair kpair = null;
- if (type == DSA) { kpair = new KeyPairDSA(jsch); }
- else if (type == RSA) { kpair = new KeyPairRSA(jsch); }
- if (kpair != null)
- {
- kpair.Generate(key_size);
- }
- return kpair;
- }
-
- internal abstract void Generate(int key_size);
-
- internal abstract byte[] Begin { get; }
-
- internal abstract byte[] End { get; }
-
- public abstract int KeySize { get; }
-
- public KeyPair(JSch jsch)
- {
- this.m_jsch = jsch;
- }
-
- internal abstract byte[] PrivateKey { get; }
-
- private void Write(Stream s, byte[] arr)
- {
- s.Write(arr, 0, arr.Length);
- }
-
- public void WritePrivateKey(Stream outs)
- {
- byte[] plain = PrivateKey;
- byte[][] _iv = new byte[1][];
- byte[] encoded = Encrypt(plain, _iv);
- byte[] iv = _iv[0];
- byte[] prv = Util.ToBase64(encoded, 0, encoded.Length);
-
- try
- {
- Write(outs, Begin);
- Write(outs, m_cr);
- if (m_passphrase != null)
- {
- Write(outs, m_header[0]); Write(outs, m_cr);
- Write(outs, m_header[1]);
- for (int j = 0; j < iv.Length; j++)
- {
- outs.WriteByte(b2a((byte)((iv[j] >> 4) & 0x0f)));
- outs.WriteByte(b2a((byte)(iv[j] & 0x0f)));
- }
- Write(outs, m_cr);
- Write(outs, m_cr);
- }
- int i = 0;
- while (i < prv.Length)
- {
- if (i + 64 < prv.Length)
- {
- outs.Write(prv, i, 64);
- Write(outs, m_cr);
- i += 64;
- continue;
- }
- outs.Write(prv, i, prv.Length - i);
- Write(outs, m_cr);
- break;
- }
- Write(outs, End); Write(outs, m_cr);
- //outs.close();
- }
- catch (Exception e)
- {
- Trace.TraceError("Error:\r\n{0}", e.ToString());
- }
- }
-
- internal abstract byte[] KeyTypeName { get; }
-
- public abstract int KeyType { get; }
-
- public virtual byte[] PublicKeyBlob { get { return m_publickeyblob; } }
-
- public void WritePublicKey(Stream outs, string comment)
- {
- byte[] pubblob = PublicKeyBlob;
- byte[] pub = Util.ToBase64(pubblob, 0, pubblob.Length);
- try
- {
- Write(outs, KeyTypeName);
- Write(outs, m_space);
- outs.Write(pub, 0, pub.Length);
- Write(outs, m_space);
- Write(outs, Util.GetBytes(comment));
- Write(outs, m_cr);
- }
- catch (Exception e)
- {
- Trace.TraceError("Error:\r\n{0}", e.ToString());
- }
- }
-
- public void WritePublicKey(string name, string comment)
- {
- FileStream fos = new FileStream(name, FileMode.OpenOrCreate);
- WritePublicKey(fos, comment);
- fos.Close();
- }
-
- public void WriteSECSHPublicKey(Stream outs, string comment)
- {
- byte[] pubblob = PublicKeyBlob;
- byte[] pub = Util.ToBase64(pubblob, 0, pubblob.Length);
- try
- {
- Write(outs, Util.GetBytes("---- BEGIN SSH2 PUBLIC KEY ----"));
- Write(outs, m_cr);
- Write(outs, Util.GetBytes("Comment: \"" + comment + "\""));
- Write(outs, m_cr);
- int index = 0;
- while (index < pub.Length)
- {
- int len = 70;
- if ((pub.Length - index) < len) len = pub.Length - index;
- outs.Write(pub, index, len); Write(outs, m_cr);
- index += len;
- }
- Write(outs, Util.GetBytes("---- END SSH2 PUBLIC KEY ----"));
- Write(outs, m_cr);
- }
- catch (Exception e)
- {
- Trace.TraceError("Error:\r\n{0}", e.ToString());
- }
- }
-
- public void writeSECSHPublicKey(string name, string comment)
- {
- FileStream fos = new FileStream(name, FileMode.OpenOrCreate);
- WriteSECSHPublicKey(fos, comment);
- fos.Close();
- }
-
- public void WritePrivateKey(string name)
- {
- FileStream fos = new FileStream(name, FileMode.OpenOrCreate);
- WritePrivateKey(fos);
- fos.Close();
- }
-
- public string GetFingerPrint()
- {
- if (m_hash == null) m_hash = GenHash();
- byte[] kblob = PublicKeyBlob;
- if (kblob == null) return null;
- return KeySize + " " + Util.GetFingerPrint(m_hash, kblob);
- }
-
- private byte[] Encrypt(byte[] plain, byte[][] _iv)
- {
- if (m_passphrase == null) return plain;
-
- if (m_cipher == null) m_cipher = GenCipher();
- byte[] iv = _iv[0] = new byte[m_cipher.IVSize];
-
- if (m_random == null) m_random = GenRandom();
- m_random.Fill(iv, 0, iv.Length);
-
- byte[] key = GenKey(m_passphrase, iv);
- byte[] encoded = plain;
- int bsize = m_cipher.BlockSize;
- if (encoded.Length % bsize != 0)
- {
- byte[] foo = new byte[(encoded.Length / bsize + 1) * bsize];
- Array.Copy(encoded, 0, foo, 0, encoded.Length);
- encoded = foo;
- }
-
- try
- {
- m_cipher.Init(Cipher.ENCRYPT_MODE, key, iv);
- m_cipher.Update(encoded, 0, encoded.Length, encoded, 0);
- }
- catch (Exception e)
- {
- Trace.TraceError("Error:\r\n{0}", e.ToString());
- }
- return encoded;
- }
-
- internal abstract bool Parse(byte[] data);
-
- private byte[] Decrypt(byte[] data, byte[] passphrase, byte[] iv)
- {
- /*
- if(iv==null){ // FSecure
- iv=new byte[8];
- for(int i=0; i<iv.Length; i++)iv[i]=0;
- }
- */
- try
- {
- byte[] key = GenKey(passphrase, iv);
- m_cipher.Init(Cipher.DECRYPT_MODE, key, iv);
- byte[] plain = new byte[data.Length];
- m_cipher.Update(data, 0, data.Length, plain, 0);
- return plain;
- }
- catch (Exception e)
- {
- Trace.TraceError("Error:\r\n{0}", e.ToString());
- }
- return null;
- }
-
- internal int WriteSEQUENCE(byte[] buf, int index, int len)
- {
- buf[index++] = 0x30;
- index = WriteLength(buf, index, len);
- return index;
- }
-
- internal int WriteINTEGER(byte[] buf, int index, byte[] data)
- {
- buf[index++] = 0x02;
- index = WriteLength(buf, index, data.Length);
- Array.Copy(data, 0, buf, index, data.Length);
- index += data.Length;
- return index;
- }
-
- internal int CountLength(int len)
- {
- int i = 1;
- if (len <= 0x7f) return i;
- while (len > 0)
- {
- len >>= 8;
- i++;
- }
- return i;
- }
-
- internal int WriteLength(byte[] data, int index, int len)
- {
- int i = CountLength(len) - 1;
- if (i == 0)
- {
- data[index++] = (byte)len;
- return index;
- }
- data[index++] = (byte)(0x80 | i);
- int j = index + i;
- while (i > 0)
- {
- data[index + i - 1] = (byte)(len & 0xff);
- len >>= 8;
- i--;
- }
- return j;
- }
-
- private IRandom GenRandom()
- {
- if (m_random == null)
- {
- try
- {
- Type t = Type.GetType(m_jsch.GetConfig("random"));
- m_random = (IRandom)Activator.CreateInstance(t);
- }
- catch (Exception e)
- {
- Trace.TraceError("connect: random " + e);
- }
- }
- return m_random;
- }
-
- private HashAlgorithm GenHash()
- {
- try
- {
- Type t = Type.GetType(m_jsch.GetConfig("md5"));
- m_hash = (HashAlgorithm)Activator.CreateInstance(t);
- m_hash.Init();
- }
- catch//(Exception e)
- {
- }
- return m_hash;
- }
-
- private Cipher GenCipher()
- {
- try
- {
- Type t;
- t = Type.GetType(m_jsch.GetConfig("3des-cbc"));
- m_cipher = (Cipher)(Activator.CreateInstance(t));
- }
- catch//(Exception e)
- {
- }
- return m_cipher;
- }
-
- /*
- hash is MD5
- h(0) <- hash(passphrase, iv);
- h(n) <- hash(h(n-1), passphrase, iv);
- key <- (h(0),...,h(n))[0,..,key.Length];
- */
- [MethodImpl(MethodImplOptions.Synchronized)]
- internal byte[] GenKey(byte[] passphrase, byte[] iv)
- {
- if (m_cipher == null) m_cipher = GenCipher();
- if (m_hash == null) m_hash = GenHash();
-
- byte[] key = new byte[m_cipher.BlockSize];
- int hsize = m_hash.BlockSize;
- byte[] hn = new byte[key.Length / hsize * hsize +
- (key.Length % hsize == 0 ? 0 : hsize)];
- try
- {
- byte[] tmp = null;
- if (vendor == VENDOR_OPENSSH)
- {
- for (int index = 0; index + hsize <= hn.Length; )
- {
- if (tmp != null) { m_hash.Update(tmp, 0, tmp.Length); }
- m_hash.Update(passphrase, 0, passphrase.Length);
- m_hash.Update(iv, 0, iv.Length);
- tmp = m_hash.Digest();
- Array.Copy(tmp, 0, hn, index, tmp.Length);
- index += tmp.Length;
- }
- Array.Copy(hn, 0, key, 0, key.Length);
- }
- else if (vendor == VENDOR_FSECURE)
- {
- for (int index = 0; index + hsize <= hn.Length; )
- {
- if (tmp != null) { m_hash.Update(tmp, 0, tmp.Length); }
- m_hash.Update(passphrase, 0, passphrase.Length);
- tmp = m_hash.Digest();
- Array.Copy(tmp, 0, hn, index, tmp.Length);
- index += tmp.Length;
- }
- Array.Copy(hn, 0, key, 0, key.Length);
- }
- }
- catch (Exception e)
- {
- Trace.TraceError("Error:\r\n{0}", e.ToString());
- }
- return key;
- }
-
- public void SetPassphrase(string passphrase)
- {
- if (passphrase == null || passphrase.Length == 0)
- {
- SetPassphrase((byte[])null);
- }
- else
- {
- SetPassphrase(Util.GetBytes(passphrase));
- }
- }
-
- public void SetPassphrase(byte[] passphrase)
- {
- if (passphrase != null && passphrase.Length == 0)
- passphrase = null;
- this.m_passphrase = passphrase;
- }
-
- public bool isEncrypted { get { return m_encrypted; } }
-
- public bool Decrypt(string _passphrase)
- {
- byte[] passphrase = Util.GetBytes(_passphrase);
- byte[] foo = Decrypt(m_data, passphrase, m_iv);
- if (Parse(foo))
- {
- m_encrypted = false;
- }
- return !m_encrypted;
- }
-
- public static KeyPair Load(JSch jsch, string prvkey)
- {
- string pubkey = prvkey + ".pub";
- // if(!new File(pubkey).exists())
- if (!File.Exists(pubkey))
- pubkey = null;
-
- return Load(jsch, prvkey, pubkey);
- }
-
- public static KeyPair Load(JSch jsch, string prvkey, string pubkey)
- {
-
- byte[] iv = new byte[8]; // 8
- bool encrypted = true;
- byte[] data = null;
-
- byte[] publickeyblob = null;
-
- int type = ERROR;
- int vendor = VENDOR_OPENSSH;
-
- try
- {
- //File file=new File(prvkey);
- FileStream fis = File.OpenRead(prvkey);
- byte[] buf = new byte[(int)(fis.Length)];
- int len = fis.Read(buf, 0, buf.Length);
- fis.Close();
-
- int i = 0;
-
- while (i < len)
- {
- if (buf[i] == 'B' && buf[i + 1] == 'E' && buf[i + 2] == 'G' && buf[i + 3] == 'I')
- {
- i += 6;
- if (buf[i] == 'D' &&
- buf[i + 1] == 'S' &&
- buf[i + 2] == 'A')
- {
- type = DSA;
- }
- else if (buf[i] == 'R' &&
- buf[i + 1] == 'S' &&
- buf[i + 2] == 'A')
- {
- type = RSA;
- }
- else if (buf[i] == 'S' &&
- buf[i + 1] == 'S' &&
- buf[i + 2] == 'H')
- { // FSecure
- type = UNKNOWN;
- vendor = VENDOR_FSECURE;
- }
- else
- {
- throw new JSchException("invaid privatekey: " + prvkey);
- }
-
- i += 3;
- continue;
- }
-
- if (buf[i] == 'C' &&
- buf[i + 1] == 'B' &&
- buf[i + 2] == 'C' &&
- buf[i + 3] == ',')
- {
- i += 4;
- for (int ii = 0; ii < iv.Length; ii++)
- {
- iv[ii] = (byte)(((a2b(buf[i++]) << 4) & 0xf0) + (a2b(buf[i++]) & 0xf));
- }
- continue;
- }
-
- if (buf[i] == 0x0d &&
- i + 1 < buf.Length &&
- buf[i + 1] == 0x0a)
- {
- i++;
- continue;
- }
-
- if (buf[i] == 0x0a && i + 1 < buf.Length)
- {
- if (buf[i + 1] == 0x0a)
- {
- i += 2;
- break;
- }
-
- if (buf[i + 1] == 0x0d &&
- i + 2 < buf.Length &&
- buf[i + 2] == 0x0a)
- {
- i += 3;
- break;
- }
-
- bool inheader = false;
- for (int j = i + 1; j < buf.Length; j++)
- {
- if (buf[j] == 0x0a) break;
- //if(buf[j]==0x0d) break;
- if (buf[j] == ':')
- {
- inheader = true; break;
- }
- }
-
- if (!inheader)
- {
- i++;
- encrypted = false; // no passphrase
- break;
- }
- }
- i++;
- }
-
- if (type == ERROR)
- throw new JSchException("invaid privatekey: " + prvkey);
-
- int start = i;
- while (i < len)
- {
- if (buf[i] == 0x0a)
- {
- bool xd = (buf[i - 1] == 0x0d);
- Array.Copy(buf, i + 1,
- buf,
- i - (xd ? 1 : 0),
- len - i - 1 - (xd ? 1 : 0)
- );
- if (xd) len--;
- len--;
- continue;
- }
- if (buf[i] == '-') { break; }
- i++;
- }
-
- data = Util.FromBase64(buf, start, i - start);
-
- if (data.Length > 4 && // FSecure
- data[0] == (byte)0x3f &&
- data[1] == (byte)0x6f &&
- data[2] == (byte)0xf9 &&
- data[3] == (byte)0xeb)
- {
-
- ByteBuffer _buf = new ByteBuffer(data);
- _buf.GetInt(); // 0x3f6ff9be
- _buf.GetInt();
- byte[] _type = _buf.GetString();
- //System.outs.println("type: "+new string(_type));
- byte[] _cipher = _buf.GetString();
- string cipher = Util.GetString(_cipher);
- //System.outs.println("cipher: "+cipher);
- if (cipher.Equals("3des-cbc"))
- {
- _buf.GetInt();
- byte[] foo = new byte[data.Length - _buf.Offset];
- _buf.GetByte(foo);
- data = foo;
- encrypted = true;
- throw new JSchException("unknown privatekey format: " + prvkey);
- }
- else if (cipher.Equals("none"))
- {
- _buf.GetInt();
- _buf.GetInt();
-
- encrypted = false;
-
- byte[] foo = new byte[data.Length - _buf.Offset];
- _buf.GetByte(foo);
- data = foo;
- }
- }
-
- if (pubkey != null)
- {
- try
- {
- //file=new File(pubkey);
- fis = File.OpenRead(pubkey);
- buf = new byte[(int)(fis.Length)];
- len = fis.Read(buf, 0, buf.Length);
- fis.Close();
-
- if (buf.Length > 4 && // FSecure's public key
- buf[0] == '-' &&
- buf[1] == '-' &&
- buf[2] == '-' &&
- buf[3] == '-')
- {
-
- bool valid = true;
- i = 0;
- do { i++; } while (buf.Length > i && buf[i] != 0x0a);
- if (buf.Length <= i)
- valid = false;
-
- while (valid)
- {
- if (buf[i] == 0x0a)
- {
- bool inheader = false;
- for (int j = i + 1; j < buf.Length; j++)
- {
- if (buf[j] == 0x0a)
- break;
- if (buf[j] == ':') { inheader = true; break; }
- }
-
- if (!inheader)
- {
- i++;
- break;
- }
- }
- i++;
- }
- if (buf.Length <= i)
- valid = false;
-
- start = i;
- while (valid && i < len)
- {
- if (buf[i] == 0x0a)
- {
- Array.Copy(buf, i + 1, buf, i, len - i - 1);
- len--;
- continue;
- }
- if (buf[i] == '-')
- break;
- i++;
- }
- if (valid)
- {
- publickeyblob = Util.FromBase64(buf, start, i - start);
- if (type == UNKNOWN)
- {
- if (publickeyblob[8] == 'd')
- type = DSA;
- else if (publickeyblob[8] == 'r')
- type = RSA;
- }
- }
- }
- else
- {
- if (buf[0] == 's' &&
- buf[1] == 's' &&
- buf[2] == 'h' &&
- buf[3] == '-')
- {
- i = 0;
- while (i < len) { if (buf[i] == ' ')break; i++; } i++;
- if (i < len)
- {
- start = i;
- while (i < len)
- {
- if (buf[i] == ' ')
- break; i++;
- }
- publickeyblob = Util.FromBase64(buf, start, i - start);
- }
- }
- }
- }
- catch//(Exception ee)
- {
- }
- }
- }
- catch (Exception e)
- {
- if (e is JSchException)
- throw (JSchException)e;
- throw new JSchException(e.ToString());
- }
-
- KeyPair kpair = null;
- if (type == DSA)
- kpair = new KeyPairDSA(jsch);
- else if (type == RSA)
- kpair = new KeyPairRSA(jsch);
-
- if (kpair != null)
- {
- kpair.m_encrypted = encrypted;
- kpair.m_publickeyblob = publickeyblob;
- kpair.vendor = vendor;
-
- if (encrypted)
- {
- kpair.m_iv = iv;
- kpair.m_data = data;
- }
- else
- {
- if (kpair.Parse(data))
- return kpair;
- else
- throw new JSchException("invaid privatekey: " + prvkey);
- }
- }
-
- return kpair;
- }
-
- static private byte a2b(byte c)
- {
- if ('0' <= c && c <= '9')
- return (byte)(c - '0');
- return (byte)(c - 'a' + 10);
- }
-
- static private byte b2a(byte c)
- {
- if (0 <= c && c <= 9)
- return (byte)(c + '0');
- return (byte)(c - 10 + 'A');
- }
-
- public virtual void Dispose()
- {
- m_passphrase = null;
- }
- }
-
- }