/* -*- Mode: java; c-basic-indent: 4; tab-width: 4 -*- */ package freenet.crypt; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import net.i2p.util.NativeBigInteger; import freenet.support.Base64; import freenet.support.HexUtil; import freenet.support.IllegalBase64Exception; //import freenet.support.SimpleFieldSet; public class DSAPublicKey extends CryptoKey { private static final long serialVersionUID = -1; private final BigInteger y; public static final int PADDED_SIZE = 1024; private final DSAGroup group; private byte[] fingerprint = null; public DSAPublicKey(DSAGroup g, BigInteger y) { if(y.signum() != 1) throw new IllegalArgumentException(); this.y=y; this.group=g; if(g == null) throw new NullPointerException(); } /** * Use this constructor if you have a Hex:ed version of y already * available, will save some conversions and string allocations. */ public DSAPublicKey(DSAGroup g, String yAsHexString) throws NumberFormatException { this.y=new NativeBigInteger(yAsHexString,16); if(y.signum() != 1) throw new IllegalArgumentException(); this.group=g; if(g == null) throw new NullPointerException(); } public DSAPublicKey(DSAGroup g, DSAPrivateKey p) { this(g,g.getG().modPow(p.getX(), g.getP())); } public DSAPublicKey(InputStream is) throws IOException, CryptFormatException { group=(DSAGroup) DSAGroup.read(is); y=Util.readMPI(is); // FIXME should check y < group.something? } public static DSAPublicKey create(byte[] pubkeyAsBytes) throws CryptFormatException { try { return new DSAPublicKey(new ByteArrayInputStream(pubkeyAsBytes)); } catch (IOException e) { throw new CryptFormatException(e); } } public BigInteger getY() { return y; } public BigInteger getP() { return group.getP(); } public BigInteger getQ() { return group.getQ(); } public BigInteger getG() { return group.getG(); } public String keyType() { return "DSA.p"; } // Nope, this is fine public DSAGroup getGroup() { return group; } // public void writeForWireWithoutGroup(OutputStream out) throws IOException { // Util.writeMPI(y, out); // } // // public void writeForWire(OutputStream out) throws IOException { // Util.writeMPI(y, out); // group.writeForWire(out); // } // // public void writeWithoutGroup(OutputStream out) // throws IOException { // write(out, getClass().getName()); // Util.writeMPI(y, out); // } // public static CryptoKey read(InputStream i) throws IOException, CryptFormatException { return new DSAPublicKey(i); } public int keyId() { return y.intValue(); } public String toLongString() { return "y="+HexUtil.biToHex(y); } // this won't correctly read the output from writeAsField //public static CryptoKey readFromField(DSAGroup group, String field) { // BigInteger y=Util.byteArrayToMPI(Util.hexToBytes(field)); // return new DSAPublicKey(group, y); //} public byte[] asBytes() { byte[] groupBytes=group.asBytes(); byte[] ybytes=Util.MPIbytes(y); byte[] bytes=new byte[groupBytes.length + ybytes.length]; System.arraycopy(groupBytes, 0, bytes, 0, groupBytes.length); System.arraycopy(ybytes, 0, bytes, groupBytes.length, ybytes.length); return bytes; } public byte[] asBytesHash() { byte[] hash = SHA256.digest(asBytes()); return hash; } public byte[] asPaddedBytes() { byte[] asBytes = asBytes(); if(asBytes.length == PADDED_SIZE) return asBytes; if(asBytes.length > PADDED_SIZE) throw new Error("Cannot fit key in "+PADDED_SIZE+" - real size is "+asBytes.length); byte[] padded = new byte[PADDED_SIZE]; System.arraycopy(asBytes, 0, padded, 0, asBytes.length); return padded; } public byte[] fingerprint() { synchronized(this) { if(fingerprint == null) fingerprint = fingerprint(new BigInteger[] {y}); return fingerprint; } } public boolean equals(DSAPublicKey o) { if(this == o) // Not necessary, but a very cheap optimization return true; return y.equals(o.y) && group.equals(o.group); } public boolean equals(Object o) { if(this == o) // Not necessary, but a very cheap optimization return true; return (o instanceof DSAPublicKey) && y.equals(((DSAPublicKey) o).y) && group.equals(((DSAPublicKey) o).group); } public int compareTo(Object other) { if (other instanceof DSAPublicKey) { return getY().compareTo(((DSAPublicKey)other).getY()); } else return -1; } public SimpleFieldSet asFieldSet() { SimpleFieldSet fs = new SimpleFieldSet(true); fs.putSingle("y", Base64.encode(y.toByteArray())); return fs; } public static DSAPublicKey create(SimpleFieldSet set, DSAGroup group) throws IllegalBase64Exception { NativeBigInteger x = new NativeBigInteger(1, Base64.decode(set.get("y"))); return new DSAPublicKey(group, x); } }