2
Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
4
Redistribution and use in source and binary forms, with or without
5
modification, are permitted provided that the following conditions are met:
7
1. Redistributions of source code must retain the above copyright notice,
8
this list of conditions and the following disclaimer.
10
2. Redistributions in binary form must reproduce the above copyright
11
notice, this list of conditions and the following disclaimer in
12
the documentation and/or other materials provided with the distribution.
14
3. The names of the authors may not be used to endorse or promote products
15
derived from this software without specific prior written permission.
17
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
18
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
20
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
21
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
This code is based on jsch (http://www.jcraft.com/jsch).
29
All credit should go to the authors of jsch.
38
public abstract class KeyPair
40
public const int ERROR = 0;
42
public const int DSA = 1;
44
public const int RSA = 2;
46
public const int UNKNOWN = 3;
48
internal const int VENDOR_OPENSSH = 0;
50
internal const int VENDOR_FSECURE = 1;
52
internal int vendor = VENDOR_OPENSSH;
54
private static readonly byte[] cr = Util.Str2byte("\n");
56
/// <exception cref="NSch.JSchException"></exception>
57
public static NSch.KeyPair GenKeyPair(JSch jsch, int type)
59
return GenKeyPair(jsch, type, 1024);
62
/// <exception cref="NSch.JSchException"></exception>
63
public static NSch.KeyPair GenKeyPair(JSch jsch, int type, int key_size)
65
NSch.KeyPair kpair = null;
68
kpair = new KeyPairDSA(jsch);
74
kpair = new KeyPairRSA(jsch);
79
kpair.Generate(key_size);
84
/// <exception cref="NSch.JSchException"></exception>
85
internal abstract void Generate(int key_size);
87
internal abstract byte[] GetBegin();
89
internal abstract byte[] GetEnd();
91
internal abstract int GetKeySize();
93
internal JSch jsch = null;
95
private NSch.Cipher cipher;
99
private Random random;
101
private byte[] passphrase;
103
public KeyPair(JSch jsch)
108
internal static byte[][] header = new byte[][] { Util.Str2byte("Proc-Type: 4,ENCRYPTED"
109
), Util.Str2byte("DEK-Info: DES-EDE3-CBC,") };
111
internal abstract byte[] GetPrivateKey();
113
public virtual void WritePrivateKey(OutputStream @out)
115
byte[] plain = GetPrivateKey();
116
byte[][] _iv = new byte[1][];
117
byte[] encoded = Encrypt(plain, _iv);
118
if (encoded != plain)
123
byte[] prv = Util.ToBase64(encoded, 0, encoded.Length);
126
@out.Write(GetBegin());
128
if (passphrase != null)
130
@out.Write(header[0]);
132
@out.Write(header[1]);
133
for (int i = 0; i < iv.Length; i++)
135
@out.Write(B2a(unchecked((byte)((iv[i] >> 4) & unchecked((int)(0x0f))))));
136
@out.Write(B2a(unchecked((byte)(iv[i] & unchecked((int)(0x0f))))));
142
while (i_1 < prv.Length)
144
if (i_1 + 64 < prv.Length)
146
@out.Write(prv, i_1, 64);
151
@out.Write(prv, i_1, prv.Length - i_1);
155
@out.Write(GetEnd());
163
private static byte[] space = Util.Str2byte(" ");
166
internal abstract byte[] GetKeyTypeName();
168
public abstract int GetKeyType();
170
public virtual byte[] GetPublicKeyBlob()
172
return publickeyblob;
175
public virtual void WritePublicKey(OutputStream @out, string comment)
177
byte[] pubblob = GetPublicKeyBlob();
178
byte[] pub = Util.ToBase64(pubblob, 0, pubblob.Length);
181
@out.Write(GetKeyTypeName());
183
@out.Write(pub, 0, pub.Length);
185
@out.Write(Util.Str2byte(comment));
193
/// <exception cref="System.IO.FileNotFoundException"></exception>
194
/// <exception cref="System.IO.IOException"></exception>
195
public virtual void WritePublicKey(string name, string comment)
197
FileOutputStream fos = new FileOutputStream(name);
198
WritePublicKey(fos, comment);
202
public virtual void WriteSECSHPublicKey(OutputStream @out, string comment)
204
byte[] pubblob = GetPublicKeyBlob();
205
byte[] pub = Util.ToBase64(pubblob, 0, pubblob.Length);
208
@out.Write(Util.Str2byte("---- BEGIN SSH2 PUBLIC KEY ----"));
210
@out.Write(Util.Str2byte("Comment: \"" + comment + "\""));
213
while (index < pub.Length)
216
if ((pub.Length - index) < len)
218
len = pub.Length - index;
220
@out.Write(pub, index, len);
224
@out.Write(Util.Str2byte("---- END SSH2 PUBLIC KEY ----"));
232
/// <exception cref="System.IO.FileNotFoundException"></exception>
233
/// <exception cref="System.IO.IOException"></exception>
234
public virtual void WriteSECSHPublicKey(string name, string comment)
236
FileOutputStream fos = new FileOutputStream(name);
237
WriteSECSHPublicKey(fos, comment);
241
/// <exception cref="System.IO.FileNotFoundException"></exception>
242
/// <exception cref="System.IO.IOException"></exception>
243
public virtual void WritePrivateKey(string name)
245
FileOutputStream fos = new FileOutputStream(name);
246
WritePrivateKey(fos);
250
public virtual string GetFingerPrint()
256
byte[] kblob = GetPublicKeyBlob();
261
return GetKeySize() + " " + Util.GetFingerPrint(hash, kblob);
264
private byte[] Encrypt(byte[] plain, byte[][] _iv)
266
if (passphrase == null)
272
cipher = GenCipher();
274
byte[] iv = _iv[0] = new byte[cipher.GetIVSize()];
277
random = GenRandom();
279
random.Fill(iv, 0, iv.Length);
280
byte[] key = GenKey(passphrase, iv);
281
byte[] encoded = plain;
284
//int bsize=cipher.getBlockSize();
285
int bsize = cipher.GetIVSize();
286
byte[] foo = new byte[(encoded.Length / bsize + 1) * bsize];
287
System.Array.Copy(encoded, 0, foo, 0, encoded.Length);
288
int padding = bsize - encoded.Length % bsize;
289
for (int i = foo.Length - 1; (foo.Length - padding) <= i; i--)
291
foo[i] = unchecked((byte)padding);
297
cipher.Init(NSch.Cipher.ENCRYPT_MODE, key, iv);
298
cipher.Update(encoded, 0, encoded.Length, encoded, 0);
303
//System.err.println(e);
308
internal abstract bool Parse(byte[] data);
310
private byte[] Decrypt(byte[] data, byte[] passphrase, byte[] iv)
314
byte[] key = GenKey(passphrase, iv);
315
cipher.Init(NSch.Cipher.DECRYPT_MODE, key, iv);
317
byte[] plain = new byte[data.Length];
318
cipher.Update(data, 0, data.Length, plain, 0);
324
//System.err.println(e);
328
internal virtual int WriteSEQUENCE(byte[] buf, int index, int len)
330
buf[index++] = unchecked((int)(0x30));
331
index = WriteLength(buf, index, len);
335
internal virtual int WriteINTEGER(byte[] buf, int index, byte[] data)
337
buf[index++] = unchecked((int)(0x02));
338
index = WriteLength(buf, index, data.Length);
339
System.Array.Copy(data, 0, buf, index, data.Length);
340
index += data.Length;
344
internal virtual int CountLength(int len)
347
if (len <= unchecked((int)(0x7f)))
353
len = (int)(((uint)len) >> 8);
359
internal virtual int WriteLength(byte[] data, int index, int len)
361
int i = CountLength(len) - 1;
364
data[index++] = unchecked((byte)len);
367
data[index++] = unchecked((byte)(unchecked((int)(0x80)) | i));
371
data[index + i - 1] = unchecked((byte)(len & unchecked((int)(0xff))));
372
len = (int)(((uint)len) >> 8);
378
private Random GenRandom()
384
Type c = Sharpen.Runtime.GetType(JSch.GetConfig("random"));
385
random = (Random)(System.Activator.CreateInstance(c));
389
System.Console.Error.WriteLine("connect: random " + e);
395
private HASH GenHash()
399
Type c = Sharpen.Runtime.GetType(JSch.GetConfig("md5"));
400
hash = (HASH)(System.Activator.CreateInstance(c));
409
private NSch.Cipher GenCipher()
414
c = Sharpen.Runtime.GetType(JSch.GetConfig("3des-cbc"));
415
cipher = (NSch.Cipher)(System.Activator.CreateInstance(c));
423
internal virtual byte[] GenKey(byte[] passphrase, byte[] iv)
429
cipher = GenCipher();
435
byte[] key = new byte[cipher.GetBlockSize()];
436
int hsize = hash.GetBlockSize();
437
byte[] hn = new byte[key.Length / hsize * hsize + (key.Length % hsize == 0 ? 0 :
442
if (vendor == VENDOR_OPENSSH)
444
for (int index = 0; index + hsize <= hn.Length; )
448
hash.Update(tmp, 0, tmp.Length);
450
hash.Update(passphrase, 0, passphrase.Length);
451
hash.Update(iv, 0, iv.Length);
453
System.Array.Copy(tmp, 0, hn, index, tmp.Length);
456
System.Array.Copy(hn, 0, key, 0, key.Length);
460
if (vendor == VENDOR_FSECURE)
462
for (int index = 0; index + hsize <= hn.Length; )
466
hash.Update(tmp, 0, tmp.Length);
468
hash.Update(passphrase, 0, passphrase.Length);
470
System.Array.Copy(tmp, 0, hn, index, tmp.Length);
473
System.Array.Copy(hn, 0, key, 0, key.Length);
479
System.Console.Error.WriteLine(e);
485
public virtual void SetPassphrase(string passphrase)
487
if (passphrase == null || passphrase.Length == 0)
489
SetPassphrase((byte[])null);
493
SetPassphrase(Util.Str2byte(passphrase));
497
public virtual void SetPassphrase(byte[] passphrase)
499
if (passphrase != null && passphrase.Length == 0)
503
this.passphrase = passphrase;
506
private bool encrypted = false;
508
private byte[] data = null;
510
private byte[] iv = null;
512
private byte[] publickeyblob = null;
514
public virtual bool IsEncrypted()
519
public virtual bool Decrypt(string _passphrase)
521
if (_passphrase == null || _passphrase.Length == 0)
525
return Decrypt(Util.Str2byte(_passphrase));
528
public virtual bool Decrypt(byte[] _passphrase)
534
if (_passphrase == null)
538
byte[] bar = new byte[_passphrase.Length];
539
System.Array.Copy(_passphrase, 0, bar, 0, bar.Length);
541
byte[] foo = Decrypt(data, _passphrase, iv);
542
Util.Bzero(_passphrase);
550
/// <exception cref="NSch.JSchException"></exception>
551
public static NSch.KeyPair Load(JSch jsch, string prvkey)
553
string pubkey = prvkey + ".pub";
554
if (!new FilePath(pubkey).Exists())
558
return Load(jsch, prvkey, pubkey);
561
/// <exception cref="NSch.JSchException"></exception>
562
public static NSch.KeyPair Load(JSch jsch, string prvkey, string pubkey)
564
byte[] iv = new byte[8];
566
bool encrypted = true;
568
byte[] publickeyblob = null;
570
int vendor = VENDOR_OPENSSH;
573
FilePath file = new FilePath(prvkey);
574
FileInputStream fis = new FileInputStream(prvkey);
575
byte[] buf = new byte[(int)(file.Length())];
579
int i = fis.Read(buf, len, buf.Length - len);
590
if (buf[i_1] == 'B' && buf[i_1 + 1] == 'E' && buf[i_1 + 2] == 'G' && buf[i_1 + 3]
594
if (buf[i_1] == 'D' && buf[i_1 + 1] == 'S' && buf[i_1 + 2] == 'A')
600
if (buf[i_1] == 'R' && buf[i_1 + 1] == 'S' && buf[i_1 + 2] == 'A')
606
if (buf[i_1] == 'S' && buf[i_1 + 1] == 'S' && buf[i_1 + 2] == 'H')
610
vendor = VENDOR_FSECURE;
614
//System.err.println("invalid format: "+identity);
615
throw new JSchException("invalid privatekey: " + prvkey);
622
if (buf[i_1] == 'C' && buf[i_1 + 1] == 'B' && buf[i_1 + 2] == 'C' && buf[i_1 + 3]
626
for (int ii = 0; ii < iv.Length; ii++)
628
iv[ii] = unchecked((byte)(((A2b(buf[i_1++]) << 4) & unchecked((int)(0xf0))) + (A2b
629
(buf[i_1++]) & unchecked((int)(0xf)))));
633
if (buf[i_1] == unchecked((int)(0x0d)) && i_1 + 1 < buf.Length && buf[i_1 + 1] ==
634
unchecked((int)(0x0a)))
639
if (buf[i_1] == unchecked((int)(0x0a)) && i_1 + 1 < buf.Length)
641
if (buf[i_1 + 1] == unchecked((int)(0x0a)))
646
if (buf[i_1 + 1] == unchecked((int)(0x0d)) && i_1 + 2 < buf.Length && buf[i_1 + 2
647
] == unchecked((int)(0x0a)))
652
bool inheader = false;
653
for (int j = i_1 + 1; j < buf.Length; j++)
655
if (buf[j] == unchecked((int)(0x0a)))
659
//if(buf[j]==0x0d) break;
678
throw new JSchException("invalid privatekey: " + prvkey);
683
if (buf[i_1] == unchecked((int)(0x0a)))
685
bool xd = (buf[i_1 - 1] == unchecked((int)(0x0d)));
686
System.Array.Copy(buf, i_1 + 1, buf, i_1 - (xd ? 1 : 0), len - i_1 - 1 - (xd ? 1 :
701
data = Util.FromBase64(buf, start, i_1 - start);
702
if (data.Length > 4 && data[0] == unchecked((byte)unchecked((int)(0x3f))) && data
703
[1] == unchecked((byte)unchecked((int)(0x6f))) && data[2] == unchecked((byte)unchecked(
704
(int)(0xf9))) && data[3] == unchecked((byte)unchecked((int)(0xeb))))
707
Buffer _buf = new Buffer(data);
711
byte[] _type = _buf.GetString();
712
//System.err.println("type: "+new String(_type));
713
byte[] _cipher = _buf.GetString();
714
string cipher = Util.Byte2str(_cipher);
715
//System.err.println("cipher: "+cipher);
716
if (cipher.Equals("3des-cbc"))
719
byte[] foo = new byte[data.Length - _buf.GetOffSet()];
723
throw new JSchException("unknown privatekey format: " + prvkey);
727
if (cipher.Equals("none"))
732
byte[] foo = new byte[data.Length - _buf.GetOffSet()];
742
file = new FilePath(pubkey);
743
fis = new FileInputStream(pubkey);
744
buf = new byte[(int)(file.Length())];
748
i_1 = fis.Read(buf, len, buf.Length - len);
756
if (buf.Length > 4 && buf[0] == '-' && buf[1] == '-' && buf[2] == '-' && buf[3] ==
759
// FSecure's public key
766
while (buf.Length > i_1 && buf[i_1] != unchecked((int)(0x0a)));
767
if (buf.Length <= i_1)
773
if (buf[i_1] == unchecked((int)(0x0a)))
775
bool inheader = false;
776
for (int j = i_1 + 1; j < buf.Length; j++)
778
if (buf[j] == unchecked((int)(0x0a)))
796
if (buf.Length <= i_1)
801
while (valid && i_1 < len)
803
if (buf[i_1] == unchecked((int)(0x0a)))
805
System.Array.Copy(buf, i_1 + 1, buf, i_1, len - i_1 - 1);
817
publickeyblob = Util.FromBase64(buf, start, i_1 - start);
820
if (publickeyblob[8] == 'd')
826
if (publickeyblob[8] == 'r')
836
if (buf[0] == 's' && buf[1] == 's' && buf[2] == 'h' && buf[3] == '-')
859
publickeyblob = Util.FromBase64(buf, start, i_1 - start);
871
if (e is JSchException)
873
throw (JSchException)e;
877
throw new JSchException(e.ToString(), (Exception)e);
879
throw new JSchException(e.ToString());
881
NSch.KeyPair kpair = null;
884
kpair = new KeyPairDSA(jsch);
890
kpair = new KeyPairRSA(jsch);
895
kpair.encrypted = encrypted;
896
kpair.publickeyblob = publickeyblob;
897
kpair.vendor = vendor;
905
if (kpair.Parse(data))
911
throw new JSchException("invalid privatekey: " + prvkey);
918
private static byte A2b(byte c)
920
if ('0' <= c && ((sbyte)c) <= '9')
922
return unchecked((byte)(c - '0'));
924
return unchecked((byte)(c - 'a' + 10));
927
private static byte B2a(byte c)
929
if (0 <= c && ((sbyte)c) <= 9)
931
return unchecked((byte)(c + '0'));
933
return unchecked((byte)(c - 10 + 'A'));
936
public virtual void Dispose()
938
Util.Bzero(passphrase);