Mercurial > 510Connectbot
comparison src/ch/ethz/ssh2/signature/DSASHA1Verify.java @ 278:d7e088fa2123 ganymed
start conversion from trilead to ganymed
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Fri, 18 Jul 2014 16:45:43 -0700 |
parents | 91a31873c42a |
children | e1c445af8e46 |
comparison
equal
deleted
inserted
replaced
277:e0da43026046 | 278:d7e088fa2123 |
---|---|
1 /* | 1 |
2 * Copyright (c) 2006-2011 Christian Plattner. All rights reserved. | 2 package com.trilead.ssh2.signature; |
3 * Please refer to the LICENSE.txt for licensing details. | |
4 */ | |
5 package ch.ethz.ssh2.signature; | |
6 | 3 |
7 import java.io.IOException; | 4 import java.io.IOException; |
8 import java.math.BigInteger; | 5 import java.math.BigInteger; |
9 import java.security.DigestException; | 6 import java.security.InvalidKeyException; |
7 import java.security.KeyFactory; | |
8 import java.security.NoSuchAlgorithmException; | |
10 import java.security.SecureRandom; | 9 import java.security.SecureRandom; |
11 | 10 import java.security.Signature; |
12 import ch.ethz.ssh2.PacketFormatException; | 11 import java.security.SignatureException; |
13 import ch.ethz.ssh2.crypto.digest.SHA1; | 12 import java.security.interfaces.DSAParams; |
14 import ch.ethz.ssh2.log.Logger; | 13 import java.security.interfaces.DSAPrivateKey; |
15 import ch.ethz.ssh2.packets.TypesReader; | 14 import java.security.interfaces.DSAPublicKey; |
16 import ch.ethz.ssh2.packets.TypesWriter; | 15 import java.security.spec.DSAPublicKeySpec; |
16 import java.security.spec.InvalidKeySpecException; | |
17 import java.security.spec.KeySpec; | |
18 | |
19 import com.trilead.ssh2.log.Logger; | |
20 import com.trilead.ssh2.packets.TypesReader; | |
21 import com.trilead.ssh2.packets.TypesWriter; | |
22 | |
17 | 23 |
18 /** | 24 /** |
19 * DSASHA1Verify. | 25 * DSASHA1Verify. |
20 * | 26 * |
21 * @author Christian Plattner | 27 * @author Christian Plattner, plattner@trilead.com |
22 * @version $Id: DSASHA1Verify.java 154 2014-04-28 11:45:02Z dkocher@sudo.ch $ | 28 * @version $Id: DSASHA1Verify.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ |
23 */ | 29 */ |
24 public class DSASHA1Verify { | 30 public class DSASHA1Verify { |
25 private static final Logger log = Logger.getLogger(DSASHA1Verify.class); | 31 private static final Logger log = Logger.getLogger(DSASHA1Verify.class); |
26 | 32 |
27 public static DSAPublicKey decodeSSHDSAPublicKey(byte[] key) throws IOException { | 33 public static DSAPublicKey decodeSSHDSAPublicKey(byte[] key) throws IOException { |
28 TypesReader tr = new TypesReader(key); | 34 TypesReader tr = new TypesReader(key); |
29 | |
30 String key_format = tr.readString(); | 35 String key_format = tr.readString(); |
31 | 36 |
32 if(!key_format.equals("ssh-dss")) { | 37 if (key_format.equals("ssh-dss") == false) |
33 throw new IllegalArgumentException("Not a ssh-dss public key"); | 38 throw new IllegalArgumentException("This is not a ssh-dss public key!"); |
34 } | |
35 | 39 |
36 BigInteger p = tr.readMPINT(); | 40 BigInteger p = tr.readMPINT(); |
37 BigInteger q = tr.readMPINT(); | 41 BigInteger q = tr.readMPINT(); |
38 BigInteger g = tr.readMPINT(); | 42 BigInteger g = tr.readMPINT(); |
39 BigInteger y = tr.readMPINT(); | 43 BigInteger y = tr.readMPINT(); |
40 | 44 |
41 if(tr.remain() != 0) { | 45 if (tr.remain() != 0) |
42 throw new PacketFormatException("Padding in DSA public key"); | 46 throw new IOException("Padding in DSA public key!"); |
43 } | 47 |
44 | 48 try { |
45 return new DSAPublicKey(p, q, g, y); | 49 KeyFactory kf = KeyFactory.getInstance("DSA"); |
50 KeySpec ks = new DSAPublicKeySpec(y, p, q, g); | |
51 return (DSAPublicKey) kf.generatePublic(ks); | |
52 } | |
53 catch (NoSuchAlgorithmException e) { | |
54 IOException ex = new IOException(); | |
55 ex.initCause(e); | |
56 throw ex; | |
57 } | |
58 catch (InvalidKeySpecException e) { | |
59 IOException ex = new IOException(); | |
60 ex.initCause(e); | |
61 throw ex; | |
62 } | |
46 } | 63 } |
47 | 64 |
48 public static byte[] encodeSSHDSAPublicKey(DSAPublicKey pk) throws IOException { | 65 public static byte[] encodeSSHDSAPublicKey(DSAPublicKey pk) throws IOException { |
49 TypesWriter tw = new TypesWriter(); | 66 TypesWriter tw = new TypesWriter(); |
50 | |
51 tw.writeString("ssh-dss"); | 67 tw.writeString("ssh-dss"); |
52 tw.writeMPInt(pk.getP()); | 68 DSAParams params = pk.getParams(); |
53 tw.writeMPInt(pk.getQ()); | 69 tw.writeMPInt(params.getP()); |
54 tw.writeMPInt(pk.getG()); | 70 tw.writeMPInt(params.getQ()); |
71 tw.writeMPInt(params.getG()); | |
55 tw.writeMPInt(pk.getY()); | 72 tw.writeMPInt(pk.getY()); |
56 | |
57 return tw.getBytes(); | 73 return tw.getBytes(); |
58 } | 74 } |
59 | 75 |
60 public static byte[] encodeSSHDSASignature(DSASignature ds) { | 76 /** |
77 * Convert from Java's signature ASN.1 encoding to the SSH spec. | |
78 * <p> | |
79 * Java ASN.1 encoding: | |
80 * <pre> | |
81 * SEQUENCE ::= { | |
82 * r INTEGER, | |
83 * s INTEGER | |
84 * } | |
85 * </pre> | |
86 */ | |
87 public static byte[] encodeSSHDSASignature(byte[] ds) { | |
61 TypesWriter tw = new TypesWriter(); | 88 TypesWriter tw = new TypesWriter(); |
62 | |
63 tw.writeString("ssh-dss"); | 89 tw.writeString("ssh-dss"); |
64 | 90 int len, index; |
65 byte[] r = ds.getR().toByteArray(); | 91 index = 3; |
66 byte[] s = ds.getS().toByteArray(); | 92 len = ds[index++] & 0xff; |
67 | 93 byte[] r = new byte[len]; |
94 System.arraycopy(ds, index, r, 0, r.length); | |
95 index = index + len + 1; | |
96 len = ds[index++] & 0xff; | |
97 byte[] s = new byte[len]; | |
98 System.arraycopy(ds, index, s, 0, s.length); | |
68 byte[] a40 = new byte[40]; | 99 byte[] a40 = new byte[40]; |
69 | 100 /* Patch (unsigned) r and s into the target array. */ |
70 /* Patch (unsigned) r and s into the target array. */ | |
71 | |
72 int r_copylen = (r.length < 20) ? r.length : 20; | 101 int r_copylen = (r.length < 20) ? r.length : 20; |
73 int s_copylen = (s.length < 20) ? s.length : 20; | 102 int s_copylen = (s.length < 20) ? s.length : 20; |
74 | |
75 System.arraycopy(r, r.length - r_copylen, a40, 20 - r_copylen, r_copylen); | 103 System.arraycopy(r, r.length - r_copylen, a40, 20 - r_copylen, r_copylen); |
76 System.arraycopy(s, s.length - s_copylen, a40, 40 - s_copylen, s_copylen); | 104 System.arraycopy(s, s.length - s_copylen, a40, 40 - s_copylen, s_copylen); |
77 | |
78 tw.writeString(a40, 0, 40); | 105 tw.writeString(a40, 0, 40); |
79 | |
80 return tw.getBytes(); | 106 return tw.getBytes(); |
81 } | 107 } |
82 | 108 |
83 public static DSASignature decodeSSHDSASignature(byte[] sig) throws IOException { | 109 public static byte[] decodeSSHDSASignature(byte[] sig) throws IOException { |
84 byte[] rsArray; | 110 byte[] rsArray = null; |
85 | 111 |
86 if(sig.length == 40) { | 112 if (sig.length == 40) { |
113 /* OK, another broken SSH server. */ | |
87 rsArray = sig; | 114 rsArray = sig; |
88 } | 115 } |
89 else { | 116 else { |
117 /* Hopefully a server obeying the standard... */ | |
90 TypesReader tr = new TypesReader(sig); | 118 TypesReader tr = new TypesReader(sig); |
91 | |
92 String sig_format = tr.readString(); | 119 String sig_format = tr.readString(); |
93 | 120 |
94 if(sig_format.equals("ssh-dss") == false) { | 121 if (sig_format.equals("ssh-dss") == false) |
95 throw new PacketFormatException("Peer sent wrong signature format"); | 122 throw new IOException("Peer sent wrong signature format"); |
96 } | |
97 | 123 |
98 rsArray = tr.readByteString(); | 124 rsArray = tr.readByteString(); |
99 | 125 |
100 if(rsArray.length != 40) { | 126 if (rsArray.length != 40) |
101 throw new PacketFormatException("Peer sent corrupt signature"); | 127 throw new IOException("Peer sent corrupt signature"); |
102 } | 128 |
103 | 129 if (tr.remain() != 0) |
104 if(tr.remain() != 0) { | 130 throw new IOException("Padding in DSA signature!"); |
105 throw new PacketFormatException("Padding in DSA signature!"); | 131 } |
106 } | 132 |
107 } | 133 int i = 0; |
108 | 134 int j = 0; |
109 /* Remember, s and r are unsigned ints. */ | 135 byte[] tmp; |
110 | 136 |
111 byte[] tmp = new byte[20]; | 137 if (rsArray[0] == 0 && rsArray[1] == 0 && rsArray[2] == 0) { |
112 | 138 j = ((rsArray[i++] << 24) & 0xff000000) | ((rsArray[i++] << 16) & 0x00ff0000) |
113 System.arraycopy(rsArray, 0, tmp, 0, 20); | 139 | ((rsArray[i++] << 8) & 0x0000ff00) | ((rsArray[i++]) & 0x000000ff); |
114 BigInteger r = new BigInteger(1, tmp); | 140 i += j; |
115 | 141 j = ((rsArray[i++] << 24) & 0xff000000) | ((rsArray[i++] << 16) & 0x00ff0000) |
116 System.arraycopy(rsArray, 20, tmp, 0, 20); | 142 | ((rsArray[i++] << 8) & 0x0000ff00) | ((rsArray[i++]) & 0x000000ff); |
117 BigInteger s = new BigInteger(1, tmp); | 143 tmp = new byte[j]; |
118 | 144 System.arraycopy(rsArray, i, tmp, 0, j); |
119 if(log.isDebugEnabled()) { | 145 rsArray = tmp; |
120 log.debug("decoded ssh-dss signature: first bytes r(" + ((rsArray[0]) & 0xff) + "), s(" | 146 } |
121 + ((rsArray[20]) & 0xff) + ")"); | 147 |
122 } | 148 /* ASN.1 */ |
123 | 149 int frst = ((rsArray[0] & 0x80) != 0 ? 1 : 0); |
124 return new DSASignature(r, s); | 150 int scnd = ((rsArray[20] & 0x80) != 0 ? 1 : 0); |
125 } | 151 /* Calculate output length */ |
126 | 152 int length = rsArray.length + 6 + frst + scnd; |
127 public static boolean verifySignature(byte[] message, DSASignature ds, DSAPublicKey dpk) throws IOException { | 153 tmp = new byte[length]; |
128 /* Inspired by Bouncycastle's DSASigner class */ | 154 /* DER-encoding to match Java */ |
129 | 155 tmp[0] = (byte) 0x30; |
130 SHA1 md = new SHA1(); | 156 |
131 md.update(message); | 157 if (rsArray.length != 40) |
132 byte[] sha_message = new byte[md.getDigestLength()]; | 158 throw new IOException("Peer sent corrupt signature"); |
159 | |
160 /* Calculate length */ | |
161 tmp[1] = (byte) 0x2c; | |
162 tmp[1] += frst; | |
163 tmp[1] += scnd; | |
164 /* First item */ | |
165 tmp[2] = (byte) 0x02; | |
166 /* First item length */ | |
167 tmp[3] = (byte) 0x14; | |
168 tmp[3] += frst; | |
169 /* Copy in the data for first item */ | |
170 System.arraycopy(rsArray, 0, tmp, 4 + frst, 20); | |
171 /* Second item */ | |
172 tmp[4 + tmp[3]] = (byte) 0x02; | |
173 /* Second item length */ | |
174 tmp[5 + tmp[3]] = (byte) 0x14; | |
175 tmp[5 + tmp[3]] += scnd; | |
176 /* Copy in the data for the second item */ | |
177 System.arraycopy(rsArray, 20, tmp, 6 + tmp[3] + scnd, 20); | |
178 /* Swap buffers */ | |
179 rsArray = tmp; | |
180 return rsArray; | |
181 } | |
182 | |
183 public static boolean verifySignature(byte[] message, byte[] ds, DSAPublicKey dpk) throws IOException { | |
133 try { | 184 try { |
134 md.digest(sha_message); | 185 Signature s = Signature.getInstance("SHA1withDSA"); |
135 } | 186 s.initVerify(dpk); |
136 catch(DigestException e) { | 187 s.update(message); |
137 throw new IOException(e); | 188 return s.verify(ds); |
138 } | 189 } |
139 | 190 catch (NoSuchAlgorithmException e) { |
140 BigInteger m = new BigInteger(1, sha_message); | 191 IOException ex = new IOException("No such algorithm"); |
141 | 192 ex.initCause(e); |
142 BigInteger r = ds.getR(); | 193 throw ex; |
143 BigInteger s = ds.getS(); | 194 } |
144 | 195 catch (InvalidKeyException e) { |
145 BigInteger g = dpk.getG(); | 196 IOException ex = new IOException("No such algorithm"); |
146 BigInteger p = dpk.getP(); | 197 ex.initCause(e); |
147 BigInteger q = dpk.getQ(); | 198 throw ex; |
148 BigInteger y = dpk.getY(); | 199 } |
149 | 200 catch (SignatureException e) { |
150 BigInteger zero = BigInteger.ZERO; | 201 IOException ex = new IOException(); |
151 | 202 ex.initCause(e); |
152 if(log.isDebugEnabled()) { | 203 throw ex; |
153 log.debug("ssh-dss signature: m: " + m.toString(16)); | 204 } |
154 log.debug("ssh-dss signature: r: " + r.toString(16)); | 205 } |
155 log.debug("ssh-dss signature: s: " + s.toString(16)); | 206 |
156 log.debug("ssh-dss signature: g: " + g.toString(16)); | 207 public static byte[] generateSignature(byte[] message, DSAPrivateKey pk, SecureRandom rnd) throws IOException { |
157 log.debug("ssh-dss signature: p: " + p.toString(16)); | |
158 log.debug("ssh-dss signature: q: " + q.toString(16)); | |
159 log.debug("ssh-dss signature: y: " + y.toString(16)); | |
160 } | |
161 | |
162 if(zero.compareTo(r) >= 0 || q.compareTo(r) <= 0) { | |
163 log.warning("ssh-dss signature: zero.compareTo(r) >= 0 || q.compareTo(r) <= 0"); | |
164 return false; | |
165 } | |
166 | |
167 if(zero.compareTo(s) >= 0 || q.compareTo(s) <= 0) { | |
168 log.warning("ssh-dss signature: zero.compareTo(s) >= 0 || q.compareTo(s) <= 0"); | |
169 return false; | |
170 } | |
171 | |
172 BigInteger w = s.modInverse(q); | |
173 | |
174 BigInteger u1 = m.multiply(w).mod(q); | |
175 BigInteger u2 = r.multiply(w).mod(q); | |
176 | |
177 u1 = g.modPow(u1, p); | |
178 u2 = y.modPow(u2, p); | |
179 | |
180 BigInteger v = u1.multiply(u2).mod(p).mod(q); | |
181 | |
182 return v.equals(r); | |
183 } | |
184 | |
185 public static DSASignature generateSignature(byte[] message, DSAPrivateKey pk, SecureRandom rnd) throws IOException { | |
186 SHA1 md = new SHA1(); | |
187 md.update(message); | |
188 byte[] sha_message = new byte[md.getDigestLength()]; | |
189 try { | 208 try { |
190 md.digest(sha_message); | 209 Signature s = Signature.getInstance("SHA1withDSA"); |
191 } | 210 s.initSign(pk); |
192 catch(DigestException e) { | 211 s.update(message); |
193 throw new IOException(e); | 212 return s.sign(); |
194 } | 213 } |
195 | 214 catch (NoSuchAlgorithmException e) { |
196 BigInteger m = new BigInteger(1, sha_message); | 215 IOException ex = new IOException(); |
197 BigInteger k; | 216 ex.initCause(e); |
198 int qBitLength = pk.getQ().bitLength(); | 217 throw ex; |
199 | 218 } |
200 do { | 219 catch (InvalidKeyException e) { |
201 k = new BigInteger(qBitLength, rnd); | 220 IOException ex = new IOException(); |
202 } | 221 ex.initCause(e); |
203 while(k.compareTo(pk.getQ()) >= 0); | 222 throw ex; |
204 | 223 } |
205 BigInteger r = pk.getG().modPow(k, pk.getP()).mod(pk.getQ()); | 224 catch (SignatureException e) { |
206 | 225 IOException ex = new IOException(); |
207 k = k.modInverse(pk.getQ()).multiply(m.add((pk).getX().multiply(r))); | 226 ex.initCause(e); |
208 | 227 throw ex; |
209 BigInteger s = k.mod(pk.getQ()); | 228 } |
210 | |
211 return new DSASignature(r, s); | |
212 } | 229 } |
213 } | 230 } |