]>
Commit | Line | Data |
---|---|---|
0763e16d JW |
1 | /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ |
2 | /* | |
3 | Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. | |
4 | ||
5 | Redistribution and use in source and binary forms, with or without | |
6 | modification, are permitted provided that the following conditions are met: | |
7 | ||
8 | 1. Redistributions of source code must retain the above copyright notice, | |
9 | this list of conditions and the following disclaimer. | |
10 | ||
11 | 2. Redistributions in binary form must reproduce the above copyright | |
12 | notice, this list of conditions and the following disclaimer in | |
13 | the documentation and/or other materials provided with the distribution. | |
14 | ||
15 | 3. The names of the authors may not be used to endorse or promote products | |
16 | derived from this software without specific prior written permission. | |
17 | ||
18 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, | |
19 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
20 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, | |
21 | INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, | |
22 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
24 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
27 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | */ | |
29 | ||
30 | package com.jcraft.jsch; | |
31 | ||
32 | public class DHG1 extends KeyExchange{ | |
33 | ||
34 | static final byte[] g={ 2 }; | |
35 | static final byte[] p={ | |
36 | (byte)0x00, | |
37 | (byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF, | |
38 | (byte)0xC9,(byte)0x0F,(byte)0xDA,(byte)0xA2,(byte)0x21,(byte)0x68,(byte)0xC2,(byte)0x34, | |
39 | (byte)0xC4,(byte)0xC6,(byte)0x62,(byte)0x8B,(byte)0x80,(byte)0xDC,(byte)0x1C,(byte)0xD1, | |
40 | (byte)0x29,(byte)0x02,(byte)0x4E,(byte)0x08,(byte)0x8A,(byte)0x67,(byte)0xCC,(byte)0x74, | |
41 | (byte)0x02,(byte)0x0B,(byte)0xBE,(byte)0xA6,(byte)0x3B,(byte)0x13,(byte)0x9B,(byte)0x22, | |
42 | (byte)0x51,(byte)0x4A,(byte)0x08,(byte)0x79,(byte)0x8E,(byte)0x34,(byte)0x04,(byte)0xDD, | |
43 | (byte)0xEF,(byte)0x95,(byte)0x19,(byte)0xB3,(byte)0xCD,(byte)0x3A,(byte)0x43,(byte)0x1B, | |
44 | (byte)0x30,(byte)0x2B,(byte)0x0A,(byte)0x6D,(byte)0xF2,(byte)0x5F,(byte)0x14,(byte)0x37, | |
45 | (byte)0x4F,(byte)0xE1,(byte)0x35,(byte)0x6D,(byte)0x6D,(byte)0x51,(byte)0xC2,(byte)0x45, | |
46 | (byte)0xE4,(byte)0x85,(byte)0xB5,(byte)0x76,(byte)0x62,(byte)0x5E,(byte)0x7E,(byte)0xC6, | |
47 | (byte)0xF4,(byte)0x4C,(byte)0x42,(byte)0xE9,(byte)0xA6,(byte)0x37,(byte)0xED,(byte)0x6B, | |
48 | (byte)0x0B,(byte)0xFF,(byte)0x5C,(byte)0xB6,(byte)0xF4,(byte)0x06,(byte)0xB7,(byte)0xED, | |
49 | (byte)0xEE,(byte)0x38,(byte)0x6B,(byte)0xFB,(byte)0x5A,(byte)0x89,(byte)0x9F,(byte)0xA5, | |
50 | (byte)0xAE,(byte)0x9F,(byte)0x24,(byte)0x11,(byte)0x7C,(byte)0x4B,(byte)0x1F,(byte)0xE6, | |
51 | (byte)0x49,(byte)0x28,(byte)0x66,(byte)0x51,(byte)0xEC,(byte)0xE6,(byte)0x53,(byte)0x81, | |
52 | (byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF | |
53 | }; | |
54 | ||
55 | private static final int SSH_MSG_KEXDH_INIT= 30; | |
56 | private static final int SSH_MSG_KEXDH_REPLY= 31; | |
57 | ||
58 | static final int RSA=0; | |
59 | static final int DSS=1; | |
60 | private int type=0; | |
61 | ||
62 | private int state; | |
63 | ||
64 | DH dh; | |
65 | // HASH sha; | |
66 | ||
67 | // byte[] K; | |
68 | // byte[] H; | |
69 | ||
70 | byte[] V_S; | |
71 | byte[] V_C; | |
72 | byte[] I_S; | |
73 | byte[] I_C; | |
74 | ||
75 | // byte[] K_S; | |
76 | ||
77 | byte[] e; | |
78 | ||
79 | private Buffer buf; | |
80 | private Packet packet; | |
81 | ||
82 | public void init(Session session, | |
83 | byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{ | |
84 | this.session=session; | |
85 | this.V_S=V_S; | |
86 | this.V_C=V_C; | |
87 | this.I_S=I_S; | |
88 | this.I_C=I_C; | |
89 | ||
90 | // sha=new SHA1(); | |
91 | // sha.init(); | |
92 | try{ | |
93 | Class c=Class.forName(session.getConfig("sha-1")); | |
94 | sha=(HASH)(c.newInstance()); | |
95 | sha.init(); | |
96 | } | |
97 | catch(Exception e){ | |
98 | System.err.println(e); | |
99 | } | |
100 | ||
101 | buf=new Buffer(); | |
102 | packet=new Packet(buf); | |
103 | ||
104 | try{ | |
105 | Class c=Class.forName(session.getConfig("dh")); | |
106 | dh=(DH)(c.newInstance()); | |
107 | dh.init(); | |
108 | } | |
109 | catch(Exception e){ | |
110 | //System.err.println(e); | |
111 | throw e; | |
112 | } | |
113 | ||
114 | dh.setP(p); | |
115 | dh.setG(g); | |
116 | ||
117 | // The client responds with: | |
118 | // byte SSH_MSG_KEXDH_INIT(30) | |
119 | // mpint e <- g^x mod p | |
120 | // x is a random number (1 < x < (p-1)/2) | |
121 | ||
122 | e=dh.getE(); | |
123 | ||
124 | packet.reset(); | |
125 | buf.putByte((byte)SSH_MSG_KEXDH_INIT); | |
126 | buf.putMPInt(e); | |
127 | session.write(packet); | |
128 | ||
129 | if(JSch.getLogger().isEnabled(Logger.INFO)){ | |
130 | JSch.getLogger().log(Logger.INFO, | |
131 | "SSH_MSG_KEXDH_INIT sent"); | |
132 | JSch.getLogger().log(Logger.INFO, | |
133 | "expecting SSH_MSG_KEXDH_REPLY"); | |
134 | } | |
135 | ||
136 | state=SSH_MSG_KEXDH_REPLY; | |
137 | } | |
138 | ||
139 | public boolean next(Buffer _buf) throws Exception{ | |
140 | int i,j; | |
141 | ||
142 | switch(state){ | |
143 | case SSH_MSG_KEXDH_REPLY: | |
144 | // The server responds with: | |
145 | // byte SSH_MSG_KEXDH_REPLY(31) | |
146 | // string server public host key and certificates (K_S) | |
147 | // mpint f | |
148 | // string signature of H | |
149 | j=_buf.getInt(); | |
150 | j=_buf.getByte(); | |
151 | j=_buf.getByte(); | |
152 | if(j!=31){ | |
153 | System.err.println("type: must be 31 "+j); | |
154 | return false; | |
155 | } | |
156 | ||
157 | K_S=_buf.getString(); | |
158 | // K_S is server_key_blob, which includes .... | |
159 | // string ssh-dss | |
160 | // impint p of dsa | |
161 | // impint q of dsa | |
162 | // impint g of dsa | |
163 | // impint pub_key of dsa | |
164 | //System.err.print("K_S: "); //dump(K_S, 0, K_S.length); | |
165 | byte[] f=_buf.getMPInt(); | |
166 | byte[] sig_of_H=_buf.getString(); | |
167 | /* | |
168 | for(int ii=0; ii<sig_of_H.length;ii++){ | |
169 | System.err.print(Integer.toHexString(sig_of_H[ii]&0xff)); | |
170 | System.err.print(": "); | |
171 | } | |
172 | System.err.println(""); | |
173 | */ | |
174 | ||
175 | dh.setF(f); | |
176 | K=dh.getK(); | |
177 | ||
178 | //The hash H is computed as the HASH hash of the concatenation of the | |
179 | //following: | |
180 | // string V_C, the client's version string (CR and NL excluded) | |
181 | // string V_S, the server's version string (CR and NL excluded) | |
182 | // string I_C, the payload of the client's SSH_MSG_KEXINIT | |
183 | // string I_S, the payload of the server's SSH_MSG_KEXINIT | |
184 | // string K_S, the host key | |
185 | // mpint e, exchange value sent by the client | |
186 | // mpint f, exchange value sent by the server | |
187 | // mpint K, the shared secret | |
188 | // This value is called the exchange hash, and it is used to authenti- | |
189 | // cate the key exchange. | |
190 | buf.reset(); | |
191 | buf.putString(V_C); buf.putString(V_S); | |
192 | buf.putString(I_C); buf.putString(I_S); | |
193 | buf.putString(K_S); | |
194 | buf.putMPInt(e); buf.putMPInt(f); | |
195 | buf.putMPInt(K); | |
196 | byte[] foo=new byte[buf.getLength()]; | |
197 | buf.getByte(foo); | |
198 | sha.update(foo, 0, foo.length); | |
199 | H=sha.digest(); | |
200 | //System.err.print("H -> "); //dump(H, 0, H.length); | |
201 | ||
202 | i=0; | |
203 | j=0; | |
204 | j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| | |
205 | ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); | |
206 | String alg=Util.byte2str(K_S, i, j); | |
207 | i+=j; | |
208 | ||
209 | boolean result=false; | |
210 | ||
211 | if(alg.equals("ssh-rsa")){ | |
212 | byte[] tmp; | |
213 | byte[] ee; | |
214 | byte[] n; | |
215 | ||
216 | type=RSA; | |
217 | ||
218 | j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| | |
219 | ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); | |
220 | tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; | |
221 | ee=tmp; | |
222 | j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| | |
223 | ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); | |
224 | tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; | |
225 | n=tmp; | |
226 | ||
227 | // SignatureRSA sig=new SignatureRSA(); | |
228 | // sig.init(); | |
229 | ||
230 | SignatureRSA sig=null; | |
231 | try{ | |
232 | Class c=Class.forName(session.getConfig("signature.rsa")); | |
233 | sig=(SignatureRSA)(c.newInstance()); | |
234 | sig.init(); | |
235 | } | |
236 | catch(Exception e){ | |
237 | System.err.println(e); | |
238 | } | |
239 | ||
240 | sig.setPubKey(ee, n); | |
241 | sig.update(H); | |
242 | result=sig.verify(sig_of_H); | |
243 | ||
244 | if(JSch.getLogger().isEnabled(Logger.INFO)){ | |
245 | JSch.getLogger().log(Logger.INFO, | |
246 | "ssh_rsa_verify: signature "+result); | |
247 | } | |
248 | ||
249 | } | |
250 | else if(alg.equals("ssh-dss")){ | |
251 | byte[] q=null; | |
252 | byte[] tmp; | |
253 | byte[] p; | |
254 | byte[] g; | |
255 | ||
256 | type=DSS; | |
257 | ||
258 | j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| | |
259 | ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); | |
260 | tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; | |
261 | p=tmp; | |
262 | j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| | |
263 | ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); | |
264 | tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; | |
265 | q=tmp; | |
266 | j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| | |
267 | ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); | |
268 | tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; | |
269 | g=tmp; | |
270 | j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| | |
271 | ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); | |
272 | tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; | |
273 | f=tmp; | |
274 | // SignatureDSA sig=new SignatureDSA(); | |
275 | // sig.init(); | |
276 | SignatureDSA sig=null; | |
277 | try{ | |
278 | Class c=Class.forName(session.getConfig("signature.dss")); | |
279 | sig=(SignatureDSA)(c.newInstance()); | |
280 | sig.init(); | |
281 | } | |
282 | catch(Exception e){ | |
283 | System.err.println(e); | |
284 | } | |
285 | sig.setPubKey(f, p, q, g); | |
286 | sig.update(H); | |
287 | result=sig.verify(sig_of_H); | |
288 | ||
289 | if(JSch.getLogger().isEnabled(Logger.INFO)){ | |
290 | JSch.getLogger().log(Logger.INFO, | |
291 | "ssh_dss_verify: signature "+result); | |
292 | } | |
293 | ||
294 | } | |
295 | else{ | |
296 | System.err.println("unknown alg"); | |
297 | } | |
298 | state=STATE_END; | |
299 | return result; | |
300 | } | |
301 | return false; | |
302 | } | |
303 | ||
304 | public String getKeyType(){ | |
305 | if(type==DSS) return "DSA"; | |
306 | return "RSA"; | |
307 | } | |
308 | ||
309 | public int getState(){return state; } | |
310 | } |