Package freenet.crypt

Source Code of freenet.crypt.DSAPublicKey

/* -*- 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 java.util.Arrays;

import net.i2p.util.NativeBigInteger;

import freenet.node.FSParseException;
import freenet.store.StorableBlock;
import freenet.support.Base64;
import freenet.support.HexUtil;
import freenet.support.IllegalBase64Exception;
import freenet.support.SimpleFieldSet;

public class DSAPublicKey extends CryptoKey implements StorableBlock {

  private static final long serialVersionUID = -1;
  private final BigInteger y;
  public static final int PADDED_SIZE = 1024;
  public static final int HASH_LENGTH = 32;
  /** Null means use Global.DSAgroupBigA. This makes persistence simpler. FIXME get rid if
   * get rid of db4o. */
  private final DSAGroup group;
  private byte[] fingerprint = null;
 
  private static final DSAGroup group(DSAGroup g) {
    if(g == null) return Global.DSAgroupBigA;
    else return g;
  }
 
  public DSAPublicKey(DSAGroup g, BigInteger y) {
    if(y.signum() != 1)
      throw new IllegalArgumentException();
    this.y = y;
    if(g == Global.DSAgroupBigA) g = null;
    this.group = g;
    if(y.compareTo(getGroup().getP()) > 0)
      throw new IllegalArgumentException("y must be < p but y=" + y + " p=" + g.getP());
  }

  /**
   * 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();
    if(g == Global.DSAgroupBigA) g = null;
    this.group = g;
  }

  public DSAPublicKey(DSAGroup g, DSAPrivateKey p) {
    this(g, g.getG().modPow(p.getX(), g.getP()));
  }

  public DSAPublicKey(InputStream is) throws IOException, CryptFormatException {
    DSAGroup g = (DSAGroup) DSAGroup.read(is);
    if(g == Global.DSAgroupBigA) g = null;
    group = g;
    y = Util.readMPI(is);
    if(y.compareTo(getGroup().getP()) > 0)
      throw new IllegalArgumentException("y must be < p but y=" + y + " p=" + getGroup().getP());
  }

  public DSAPublicKey(byte[] pubkeyBytes) throws IOException, CryptFormatException {
    this(new ByteArrayInputStream(pubkeyBytes));
  }

  private DSAPublicKey(DSAPublicKey key) {
    fingerprint = null; // regen when needed
    this.y = new NativeBigInteger(1, key.y.toByteArray());
    DSAGroup g = key.group;
    if(g != null) g = g.cloneKey();
    this.group = g;
  }

  public static DSAPublicKey create(byte[] pubkeyAsBytes) throws CryptFormatException {
    try {
      return new DSAPublicKey(new ByteArrayInputStream(pubkeyAsBytes));
    } catch(IOException e) {
      throw new CryptFormatException(e);
    }
  }
 
  protected DSAPublicKey() {
      // For serialization.
      y = null;
      group = null;
  }

  public BigInteger getY() {
    return y;
  }

  public BigInteger getP() {
    return getGroup().getP();
  }

  public BigInteger getQ() {
    return getGroup().getQ();
  }

  public BigInteger getG() {
    return getGroup().getG();
  }

  @Override
  public String keyType() {
    return "DSA.p";
  }

  // Nope, this is fine
  public final DSAGroup getGroup() {
    if(group == null) return Global.DSAgroupBigA;
    else 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();
  }

  @Override
  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);
  //}
  @Override
  public byte[] asBytes() {
    byte[] groupBytes = getGroup().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);
    return Arrays.copyOf(asBytes, PADDED_SIZE);
  }

  @Override
  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) && getGroup().equals(o.getGroup());
  }

  @Override
  public int hashCode() {
    return y.hashCode() ^ getGroup().hashCode();
  }

  @Override
  public boolean equals(Object o) {
    if(this == o) // Not necessary, but a very cheap optimization
      return true;
    else if((o == null) || (o.getClass() != this.getClass()))
      return false;
    return y.equals(((DSAPublicKey) o).y) && getGroup().equals(((DSAPublicKey) o).getGroup());
  }

  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 FSParseException {
    NativeBigInteger x;
    try {
      x = new NativeBigInteger(1, Base64.decode(set.get("y")));
    } catch (IllegalBase64Exception e) {
      throw new FSParseException(e);
    }
    try {
      return new DSAPublicKey(group, x);
    } catch (IllegalArgumentException e) {
      throw new FSParseException(e);
    }
  }

  @Override
  public byte[] getFullKey() {
    return asBytesHash();
  }

  @Override
  public byte[] getRoutingKey() {
    return asBytesHash();
  }

  public DSAPublicKey cloneKey() {
    return new DSAPublicKey(this);
  }

}
TOP

Related Classes of freenet.crypt.DSAPublicKey

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.