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 }