1 2 package ch.ethz.ssh2.signature; 3 4 import java.io.IOException ; 5 import java.math.BigInteger ; 6 7 import ch.ethz.ssh2.crypto.SimpleDERReader; 8 import ch.ethz.ssh2.crypto.digest.SHA1; 9 import ch.ethz.ssh2.log.Logger; 10 import ch.ethz.ssh2.packets.TypesReader; 11 import ch.ethz.ssh2.packets.TypesWriter; 12 13 19 public class RSASHA1Verify 20 { 21 private static final Logger log = Logger.getLogger(RSASHA1Verify.class); 22 23 public static RSAPublicKey decodeSSHRSAPublicKey(byte[] key) throws IOException 24 { 25 TypesReader tr = new TypesReader(key); 26 27 String key_format = tr.readString(); 28 29 if (key_format.equals("ssh-rsa") == false) 30 throw new IllegalArgumentException ("This is not a ssh-rsa public key"); 31 32 BigInteger e = tr.readMPINT(); 33 BigInteger n = tr.readMPINT(); 34 35 if (tr.remain() != 0) 36 throw new IOException ("Padding in RSA public key!"); 37 38 return new RSAPublicKey(e, n); 39 } 40 41 public static byte[] encodeSSHRSAPublicKey(RSAPublicKey pk) throws IOException 42 { 43 TypesWriter tw = new TypesWriter(); 44 45 tw.writeString("ssh-rsa"); 46 tw.writeMPInt(pk.getE()); 47 tw.writeMPInt(pk.getN()); 48 49 return tw.getBytes(); 50 } 51 52 public static RSASignature decodeSSHRSASignature(byte[] sig) throws IOException 53 { 54 TypesReader tr = new TypesReader(sig); 55 56 String sig_format = tr.readString(); 57 58 if (sig_format.equals("ssh-rsa") == false) 59 throw new IOException ("Peer sent wrong signature format"); 60 61 65 66 byte[] s = tr.readByteString(); 67 68 if (s.length == 0) 69 throw new IOException ("Error in RSA signature, S is empty."); 70 71 if (log.isEnabled()) 72 { 73 log.log(80, "Decoding ssh-rsa signature string (length: " + s.length + ")"); 74 } 75 76 if (tr.remain() != 0) 77 throw new IOException ("Padding in RSA signature!"); 78 79 return new RSASignature(new BigInteger (1, s)); 80 } 81 82 public static byte[] encodeSSHRSASignature(RSASignature sig) throws IOException 83 { 84 TypesWriter tw = new TypesWriter(); 85 86 tw.writeString("ssh-rsa"); 87 88 92 93 byte[] s = sig.getS().toByteArray(); 94 95 96 97 if ((s.length > 1) && (s[0] == 0x00)) 98 tw.writeString(s, 1, s.length - 1); 99 else 100 tw.writeString(s, 0, s.length); 101 102 return tw.getBytes(); 103 } 104 105 public static RSASignature generateSignature(byte[] message, RSAPrivateKey pk) throws IOException 106 { 107 SHA1 md = new SHA1(); 108 md.update(message); 109 byte[] sha_message = new byte[md.getDigestLength()]; 110 md.digest(sha_message); 111 112 byte[] der_header = new byte[] { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 113 0x04, 0x14 }; 114 115 int rsa_block_len = (pk.getN().bitLength() + 7) / 8; 116 117 int num_pad = rsa_block_len - (2 + der_header.length + sha_message.length) - 1; 118 119 if (num_pad < 8) 120 throw new IOException ("Cannot sign with RSA, message too long"); 121 122 byte[] sig = new byte[der_header.length + sha_message.length + 2 + num_pad]; 123 124 sig[0] = 0x01; 125 126 for (int i = 0; i < num_pad; i++) 127 { 128 sig[i + 1] = (byte) 0xff; 129 } 130 131 sig[num_pad + 1] = 0x00; 132 133 System.arraycopy(der_header, 0, sig, 2 + num_pad, der_header.length); 134 System.arraycopy(sha_message, 0, sig, 2 + num_pad + der_header.length, sha_message.length); 135 136 BigInteger m = new BigInteger (1, sig); 137 138 BigInteger s = m.modPow(pk.getD(), pk.getN()); 139 140 return new RSASignature(s); 141 } 142 143 public static boolean verifySignature(byte[] message, RSASignature ds, RSAPublicKey dpk) throws IOException 144 { 145 SHA1 md = new SHA1(); 146 md.update(message); 147 byte[] sha_message = new byte[md.getDigestLength()]; 148 md.digest(sha_message); 149 150 BigInteger n = dpk.getN(); 151 BigInteger e = dpk.getE(); 152 BigInteger s = ds.getS(); 153 154 if (n.compareTo(s) <= 0) 155 { 156 log.log(20, "ssh-rsa signature: n.compareTo(s) <= 0"); 157 return false; 158 } 159 160 int rsa_block_len = (n.bitLength() + 7) / 8; 161 162 163 164 if (rsa_block_len < 1) 165 { 166 log.log(20, "ssh-rsa signature: rsa_block_len < 1"); 167 return false; 168 } 169 170 byte[] v = s.modPow(e, n).toByteArray(); 171 172 int startpos = 0; 173 174 if ((v.length > 0) && (v[0] == 0x00)) 175 startpos++; 176 177 if ((v.length - startpos) != (rsa_block_len - 1)) 178 { 179 log.log(20, "ssh-rsa signature: (v.length - startpos) != (rsa_block_len - 1)"); 180 return false; 181 } 182 183 if (v[startpos] != 0x01) 184 { 185 log.log(20, "ssh-rsa signature: v[startpos] != 0x01"); 186 return false; 187 } 188 189 int pos = startpos + 1; 190 191 while (true) 192 { 193 if (pos >= v.length) 194 { 195 log.log(20, "ssh-rsa signature: pos >= v.length"); 196 return false; 197 } 198 if (v[pos] == 0x00) 199 break; 200 if (v[pos] != (byte) 0xff) 201 { 202 log.log(20, "ssh-rsa signature: v[pos] != (byte) 0xff"); 203 return false; 204 } 205 pos++; 206 } 207 208 int num_pad = pos - (startpos + 1); 209 210 if (num_pad < 8) 211 { 212 log.log(20, "ssh-rsa signature: num_pad < 8"); 213 return false; 214 } 215 216 pos++; 217 218 if (pos >= v.length) 219 { 220 log.log(20, "ssh-rsa signature: pos >= v.length"); 221 return false; 222 } 223 224 SimpleDERReader dr = new SimpleDERReader(v, pos, v.length - pos); 225 226 byte[] seq = dr.readSequenceAsByteArray(); 227 228 if (dr.available() != 0) 229 { 230 log.log(20, "ssh-rsa signature: dr.available() != 0"); 231 return false; 232 } 233 234 dr.resetInput(seq); 235 236 237 238 byte digestAlgorithm[] = dr.readSequenceAsByteArray(); 239 240 241 242 if ((digestAlgorithm.length < 8) || (digestAlgorithm.length > 9)) 243 { 244 log.log(20, "ssh-rsa signature: (digestAlgorithm.length < 8) || (digestAlgorithm.length > 9)"); 245 return false; 246 } 247 248 byte[] digestAlgorithm_sha1 = new byte[] { 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00 }; 249 250 for (int i = 0; i < digestAlgorithm.length; i++) 251 { 252 if (digestAlgorithm[i] != digestAlgorithm_sha1[i]) 253 { 254 log.log(20, "ssh-rsa signature: digestAlgorithm[i] != digestAlgorithm_sha1[i]"); 255 return false; 256 } 257 } 258 259 byte[] digest = dr.readOctetString(); 260 261 if (dr.available() != 0) 262 { 263 log.log(20, "ssh-rsa signature: dr.available() != 0 (II)"); 264 return false; 265 } 266 267 if (digest.length != sha_message.length) 268 { 269 log.log(20, "ssh-rsa signature: digest.length != sha_message.length"); 270 return false; 271 } 272 273 for (int i = 0; i < sha_message.length; i++) 274 { 275 if (sha_message[i] != digest[i]) 276 { 277 log.log(20, "ssh-rsa signature: sha_message[i] != digest[i]"); 278 return false; 279 } 280 } 281 282 return true; 283 } 284 } 285 | Popular Tags |