/** * Verifies the DSA signature of a signed update file. * * @param signedFile The signed update file to check. * @param signingPublicKey An instance of {@link net.i2p.data.SigningPublicKey} to use for * verification. * @return <code>true</code> if the file has a valid signature, otherwise <code>false</code>. */ public boolean verify(File signedFile, SigningPublicKey signingPublicKey) { FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream(signedFile); Signature signature = new Signature(); signature.readBytes(fileInputStream); return _context.dsa().verifySignature(signature, fileInputStream, signingPublicKey); } catch (IOException ioe) { if (_log.shouldLog(Log.WARN)) _log.warn("Error reading " + signedFile + " to verify", ioe); return false; } catch (DataFormatException dfe) { if (_log.shouldLog(Log.ERROR)) _log.error("Error reading the signature", dfe); return false; } finally { if (fileInputStream != null) try { fileInputStream.close(); } catch (IOException ioe) { } } }
/** @param sigprop The signature property to set */ private void signIt(SigningPrivateKey spk, String sigprop) { if (props == null) throw new IllegalStateException(); if (props.containsKey(sigprop)) throw new IllegalStateException(); StringWriter buf = new StringWriter(1024); buf.append(name); buf.append(KV_SEPARATOR); buf.append(dest); try { writeProps(buf); } catch (IOException ioe) { throw new IllegalStateException(ioe); } Signature s = DSAEngine.getInstance().sign(DataHelper.getUTF8(buf.toString()), spk); if (s == null) throw new IllegalArgumentException("sig failed"); props.setProperty(sigprop, s.toBase64()); }
public void readBytes(InputStream rawConfig) throws DataFormatException, IOException { _destination = Destination.create(rawConfig); _options = DataHelper.readProperties(rawConfig); _creationDate = DataHelper.readDate(rawConfig); _signature = new Signature(); _signature.readBytes(rawConfig); }
/** * Sign as a "remove" line #!dest=dest#name=name#k1=v1#sig=sig...] Must have been constructed with * non-null properties. */ public void signRemove(SigningPrivateKey spk) { if (props == null) throw new IllegalStateException(); if (props.containsKey(PROP_SIG)) throw new IllegalStateException(); props.setProperty(PROP_NAME, name); props.setProperty(PROP_DEST, dest); StringWriter buf = new StringWriter(1024); try { writeProps(buf); } catch (IOException ioe) { throw new IllegalStateException(ioe); } props.remove(PROP_NAME); props.remove(PROP_DEST); Signature s = DSAEngine.getInstance().sign(DataHelper.getUTF8(buf.toString()), spk); if (s == null) throw new IllegalArgumentException("sig failed"); props.setProperty(PROP_SIG, s.toBase64()); }
public void writeBytes(OutputStream out) throws DataFormatException, IOException { if ((_destination == null) || (_options == null) || (_signature == null) || (_creationDate == null)) throw new DataFormatException("Not enough data to create the session config"); _destination.writeBytes(out); DataHelper.writeProperties(out, _options, true); // UTF-8 DataHelper.writeDate(out, _creationDate); _signature.writeBytes(out); }
public String getProof() { StringBuilder buf = new StringBuilder(512); RouterInfo us = _context.router().getRouterInfo(); buf.append("Hash: ").append(us.getIdentity().calculateHash().toBase64()).append('\n'); // buf.append("Ident: ").append(us.getIdentity().toBase64()).append('\n'); for (RouterAddress addr : us.getAddresses()) { buf.append(addr.getTransportStyle()).append(": ").append(addr.getHost()).append('\n'); } buf.append("Caps: ").append(us.getCapabilities()).append('\n'); buf.append("Date: ").append(new Date()); // no trailing newline String msg = buf.toString(); byte[] data = DataHelper.getUTF8(msg); Signature sig = _context.dsa().sign(data, _context.keyManager().getSigningPrivateKey()); buf.setLength(0); buf.append("---BEGIN I2P SIGNED MESSAGE---\n"); buf.append(msg); buf.append("\n---BEGIN I2P SIGNATURE---\n"); buf.append(sig.toBase64()); buf.append("\n---END I2P SIGNATURE---"); return buf.toString(); }
/** * @param hash either a Hash or a SHA1Hash * @since 0.8.3 */ private boolean verifySig( Signature signature, SimpleDataStructure hash, SigningPublicKey verifyingKey) { long start = _context.clock().now(); try { byte[] sigbytes = signature.getData(); byte rbytes[] = new byte[20]; byte sbytes[] = new byte[20]; // System.arraycopy(sigbytes, 0, rbytes, 0, 20); // System.arraycopy(sigbytes, 20, sbytes, 0, 20); for (int x = 0; x < 40; x++) { if (x < 20) { rbytes[x] = sigbytes[x]; } else { sbytes[x - 20] = sigbytes[x]; } } BigInteger s = new NativeBigInteger(1, sbytes); BigInteger r = new NativeBigInteger(1, rbytes); BigInteger y = new NativeBigInteger(1, verifyingKey.getData()); BigInteger w = null; try { w = s.modInverse(CryptoConstants.dsaq); } catch (ArithmeticException ae) { _log.warn("modInverse() error", ae); return false; } byte data[] = hash.getData(); NativeBigInteger bi = new NativeBigInteger(1, data); BigInteger u1 = bi.multiply(w).mod(CryptoConstants.dsaq); BigInteger u2 = r.multiply(w).mod(CryptoConstants.dsaq); BigInteger modval = CryptoConstants.dsag.modPow(u1, CryptoConstants.dsap); BigInteger modmulval = modval.multiply(y.modPow(u2, CryptoConstants.dsap)); BigInteger v = (modmulval).mod(CryptoConstants.dsap).mod(CryptoConstants.dsaq); boolean ok = v.compareTo(r) == 0; long diff = _context.clock().now() - start; if (diff > 1000) { if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to verify the signature (" + diff + "ms)"); } return ok; } catch (Exception e) { _log.log(Log.CRIT, "Error verifying the signature", e); return false; } }
/** * Verify: Alice's IP + Alice's port + Bob's IP + Bob's port + Alice's new relay tag + Bob's * signed on time Caller must synch on this. */ private boolean verifySessionCreated() { byte signed[] = new byte [256 + 256 // X + Y + _aliceIP.length + 2 + _bobIP.length + 2 + 4 // sent relay tag + 4 // signed on time ]; int off = 0; System.arraycopy(_sentX, 0, signed, off, _sentX.length); off += _sentX.length; System.arraycopy(_receivedY, 0, signed, off, _receivedY.length); off += _receivedY.length; System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length); off += _aliceIP.length; DataHelper.toLong(signed, off, 2, _alicePort); off += 2; System.arraycopy(_bobIP, 0, signed, off, _bobIP.length); off += _bobIP.length; DataHelper.toLong(signed, off, 2, _bobPort); off += 2; DataHelper.toLong(signed, off, 4, _receivedRelayTag); off += 4; DataHelper.toLong(signed, off, 4, _receivedSignedOnTime); boolean valid = _context .dsa() .verifySignature(_receivedSignature, signed, _remotePeer.getSigningPublicKey()); if (_log.shouldLog(Log.DEBUG) || (_log.shouldLog(Log.WARN) && !valid)) { StringBuilder buf = new StringBuilder(128); buf.append("Signed sessionCreated:"); buf.append(" Alice: ").append(Addresses.toString(_aliceIP, _alicePort)); buf.append(" Bob: ").append(Addresses.toString(_bobIP, _bobPort)); buf.append(" RelayTag: ").append(_receivedRelayTag); buf.append(" SignedOn: ").append(_receivedSignedOnTime); buf.append(" signature: ").append(Base64.encode(_receivedSignature.getData())); if (valid) _log.debug(buf.toString()); else if (_log.shouldLog(Log.WARN)) _log.warn("INVALID: " + buf.toString()); } return valid; }
/** * Alternate to verifySignature() using java.security libraries. * * @throws GeneralSecurityException if algorithm unvailable or on other errors * @since 0.8.7 */ private boolean altVerifySigSHA1(Signature signature, byte[] data, SigningPublicKey verifyingKey) throws GeneralSecurityException { java.security.Signature jsig = java.security.Signature.getInstance("SHA1withDSA"); KeyFactory keyFact = KeyFactory.getInstance("DSA"); // y p q g KeySpec spec = new DSAPublicKeySpec( new NativeBigInteger(1, verifyingKey.getData()), CryptoConstants.dsap, CryptoConstants.dsaq, CryptoConstants.dsag); PublicKey pubKey = keyFact.generatePublic(spec); jsig.initVerify(pubKey); jsig.update(data); boolean rv = jsig.verify(sigBytesToASN1(signature.getData())); // if (!rv) { // System.out.println("BAD SIG\n" + net.i2p.util.HexDump.dump(signature.getData())); // System.out.println("BAD SIG\n" + // net.i2p.util.HexDump.dump(sigBytesToASN1(signature.getData()))); // } return rv; }
/** * @param hash either a Hash or a SHA1Hash * @since 0.8.3 */ private Signature signIt(SimpleDataStructure hash, SigningPrivateKey signingKey) { if ((signingKey == null) || (hash == null)) return null; long start = _context.clock().now(); Signature sig = new Signature(); BigInteger k; boolean ok = false; do { k = new BigInteger(160, _context.random()); ok = k.compareTo(CryptoConstants.dsaq) != 1; ok = ok && !k.equals(BigInteger.ZERO); // System.out.println("K picked (ok? " + ok + "): " + k.bitLength() + ": " + k.toString()); } while (!ok); BigInteger r = CryptoConstants.dsag.modPow(k, CryptoConstants.dsap).mod(CryptoConstants.dsaq); BigInteger kinv = k.modInverse(CryptoConstants.dsaq); BigInteger M = new NativeBigInteger(1, hash.getData()); BigInteger x = new NativeBigInteger(1, signingKey.getData()); BigInteger s = (kinv.multiply(M.add(x.multiply(r)))).mod(CryptoConstants.dsaq); byte[] rbytes = r.toByteArray(); byte[] sbytes = s.toByteArray(); byte[] out = new byte[40]; // (q^random)%p is computationally random _context.random().harvester().feedEntropy("DSA.sign", rbytes, 0, rbytes.length); if (rbytes.length == 20) { // System.arraycopy(rbytes, 0, out, 0, 20); for (int i = 0; i < 20; i++) { out[i] = rbytes[i]; } } else if (rbytes.length == 21) { // System.arraycopy(rbytes, 1, out, 0, 20); for (int i = 0; i < 20; i++) { out[i] = rbytes[i + 1]; } } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Using short rbytes.length [" + rbytes.length + "]"); // System.arraycopy(rbytes, 0, out, 20 - rbytes.length, rbytes.length); for (int i = 0; i < rbytes.length; i++) out[i + 20 - rbytes.length] = rbytes[i]; } if (sbytes.length == 20) { // System.arraycopy(sbytes, 0, out, 20, 20); for (int i = 0; i < 20; i++) { out[i + 20] = sbytes[i]; } } else if (sbytes.length == 21) { // System.arraycopy(sbytes, 1, out, 20, 20); for (int i = 0; i < 20; i++) { out[i + 20] = sbytes[i + 1]; } } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Using short sbytes.length [" + sbytes.length + "]"); // System.arraycopy(sbytes, 0, out, 40 - sbytes.length, sbytes.length); for (int i = 0; i < sbytes.length; i++) out[i + 20 + 20 - sbytes.length] = sbytes[i]; } sig.setData(out); long diff = _context.clock().now() - start; if (diff > 1000) { if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to sign (" + diff + "ms)"); } return sig; }
/** * Uses the given {@link net.i2p.data.SigningPrivateKey} to sign the given input file along with * its version string using DSA. The output will be a signed update file where the first 40 bytes * are the resulting DSA signature, the next 16 bytes are the input file's version string encoded * in UTF-8 (padded with trailing <code>0h</code> characters if necessary), and the remaining * bytes are the raw bytes of the input file. * * @param inputFile The file to be signed. * @param signedFile The signed update file to write. * @param signingPrivateKey An instance of <code>SigningPrivateKey</code> to sign <code>inputFile * </code> with. * @param version The version string of the input file. If this is longer than 16 characters it * will be truncated. * @return An instance of {@link net.i2p.data.Signature}, or <code>null</code> if there was an * error. */ public Signature sign( String inputFile, String signedFile, SigningPrivateKey signingPrivateKey, String version) { byte[] versionHeader = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; byte[] versionRawBytes = null; if (version.length() > VERSION_BYTES) version = version.substring(0, VERSION_BYTES); try { versionRawBytes = version.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("wtf, your JVM doesnt support utf-8? " + e.getMessage()); } System.arraycopy(versionRawBytes, 0, versionHeader, 0, versionRawBytes.length); FileInputStream fileInputStream = null; Signature signature = null; SequenceInputStream bytesToSignInputStream = null; ByteArrayInputStream versionHeaderInputStream = null; try { fileInputStream = new FileInputStream(inputFile); versionHeaderInputStream = new ByteArrayInputStream(versionHeader); bytesToSignInputStream = new SequenceInputStream(versionHeaderInputStream, fileInputStream); signature = _context.dsa().sign(bytesToSignInputStream, signingPrivateKey); } catch (Exception e) { if (_log.shouldLog(Log.ERROR)) _log.error("Error signing", e); return null; } finally { if (bytesToSignInputStream != null) try { bytesToSignInputStream.close(); } catch (IOException ioe) { } fileInputStream = null; } FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(signedFile); fileOutputStream.write(signature.getData()); fileOutputStream.write(versionHeader); fileInputStream = new FileInputStream(inputFile); byte[] buffer = new byte[1024]; int bytesRead = 0; while ((bytesRead = fileInputStream.read(buffer)) != -1) fileOutputStream.write(buffer, 0, bytesRead); fileOutputStream.close(); } catch (IOException ioe) { if (_log.shouldLog(Log.WARN)) _log.log(Log.WARN, "Error writing signed file " + signedFile, ioe); return null; } finally { if (fileInputStream != null) try { fileInputStream.close(); } catch (IOException ioe) { } if (fileOutputStream != null) try { fileOutputStream.close(); } catch (IOException ioe) { } } return signature; }