| package org.bouncycastle.asn1.eac; |
| |
| import java.math.BigInteger; |
| import java.util.Enumeration; |
| |
| import org.bouncycastle.asn1.ASN1EncodableVector; |
| import org.bouncycastle.asn1.ASN1ObjectIdentifier; |
| import org.bouncycastle.asn1.ASN1OctetString; |
| import org.bouncycastle.asn1.ASN1Primitive; |
| import org.bouncycastle.asn1.ASN1Sequence; |
| import org.bouncycastle.asn1.ASN1TaggedObject; |
| import org.bouncycastle.asn1.DEROctetString; |
| import org.bouncycastle.asn1.DERSequence; |
| import org.bouncycastle.asn1.DERTaggedObject; |
| import org.bouncycastle.util.Arrays; |
| |
| /** |
| * an Iso7816ECDSAPublicKeyStructure structure. |
| * <pre> |
| * Certificate Holder Authorization ::= SEQUENCE { |
| * ASN1TaggedObject primeModulusP; // OPTIONAL |
| * ASN1TaggedObject firstCoefA; // OPTIONAL |
| * ASN1TaggedObject secondCoefB; // OPTIONAL |
| * ASN1TaggedObject basePointG; // OPTIONAL |
| * ASN1TaggedObject orderOfBasePointR; // OPTIONAL |
| * ASN1TaggedObject publicPointY; //REQUIRED |
| * ASN1TaggedObject cofactorF; // OPTIONAL |
| * } |
| * </pre> |
| */ |
| public class ECDSAPublicKey |
| extends PublicKeyDataObject |
| { |
| private ASN1ObjectIdentifier usage; |
| private BigInteger primeModulusP; // OPTIONAL |
| private BigInteger firstCoefA; // OPTIONAL |
| private BigInteger secondCoefB; // OPTIONAL |
| private byte[] basePointG; // OPTIONAL |
| private BigInteger orderOfBasePointR; // OPTIONAL |
| private byte[] publicPointY; //REQUIRED |
| private BigInteger cofactorF; // OPTIONAL |
| private int options; |
| private static final int P = 0x01; |
| private static final int A = 0x02; |
| private static final int B = 0x04; |
| private static final int G = 0x08; |
| private static final int R = 0x10; |
| private static final int Y = 0x20; |
| private static final int F = 0x40; |
| |
| ECDSAPublicKey(ASN1Sequence seq) |
| throws IllegalArgumentException |
| { |
| Enumeration en = seq.getObjects(); |
| |
| this.usage = ASN1ObjectIdentifier.getInstance(en.nextElement()); |
| |
| options = 0; |
| while (en.hasMoreElements()) |
| { |
| Object obj = en.nextElement(); |
| |
| if (obj instanceof ASN1TaggedObject) |
| { |
| ASN1TaggedObject to = (ASN1TaggedObject)obj; |
| switch (to.getTagNo()) |
| { |
| case 0x1: |
| setPrimeModulusP(UnsignedInteger.getInstance(to).getValue()); |
| break; |
| case 0x2: |
| setFirstCoefA(UnsignedInteger.getInstance(to).getValue()); |
| break; |
| case 0x3: |
| setSecondCoefB(UnsignedInteger.getInstance(to).getValue()); |
| break; |
| case 0x4: |
| setBasePointG(ASN1OctetString.getInstance(to, false)); |
| break; |
| case 0x5: |
| setOrderOfBasePointR(UnsignedInteger.getInstance(to).getValue()); |
| break; |
| case 0x6: |
| setPublicPointY(ASN1OctetString.getInstance(to, false)); |
| break; |
| case 0x7: |
| setCofactorF(UnsignedInteger.getInstance(to).getValue()); |
| break; |
| default: |
| options = 0; |
| throw new IllegalArgumentException("Unknown Object Identifier!"); |
| } |
| } |
| else |
| { |
| throw new IllegalArgumentException("Unknown Object Identifier!"); |
| } |
| } |
| if (options != 0x20 && options != 0x7F) |
| { |
| throw new IllegalArgumentException("All options must be either present or absent!"); |
| } |
| } |
| |
| public ECDSAPublicKey(ASN1ObjectIdentifier usage, byte[] ppY) |
| throws IllegalArgumentException |
| { |
| this.usage = usage; |
| setPublicPointY(new DEROctetString(ppY)); |
| } |
| |
| public ECDSAPublicKey(ASN1ObjectIdentifier usage, BigInteger p, BigInteger a, BigInteger b, byte[] basePoint, BigInteger order, byte[] publicPoint, int cofactor) |
| { |
| this.usage = usage; |
| setPrimeModulusP(p); |
| setFirstCoefA(a); |
| setSecondCoefB(b); |
| setBasePointG(new DEROctetString(basePoint)); |
| setOrderOfBasePointR(order); |
| setPublicPointY(new DEROctetString(publicPoint)); |
| setCofactorF(BigInteger.valueOf(cofactor)); |
| } |
| |
| public ASN1ObjectIdentifier getUsage() |
| { |
| return usage; |
| } |
| |
| public byte[] getBasePointG() |
| { |
| if ((options & G) != 0) |
| { |
| return Arrays.clone(basePointG); |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| private void setBasePointG(ASN1OctetString basePointG) |
| throws IllegalArgumentException |
| { |
| if ((options & G) == 0) |
| { |
| options |= G; |
| this.basePointG = basePointG.getOctets(); |
| } |
| else |
| { |
| throw new IllegalArgumentException("Base Point G already set"); |
| } |
| } |
| |
| public BigInteger getCofactorF() |
| { |
| if ((options & F) != 0) |
| { |
| return cofactorF; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| private void setCofactorF(BigInteger cofactorF) |
| throws IllegalArgumentException |
| { |
| if ((options & F) == 0) |
| { |
| options |= F; |
| this.cofactorF = cofactorF; |
| } |
| else |
| { |
| throw new IllegalArgumentException("Cofactor F already set"); |
| } |
| } |
| |
| public BigInteger getFirstCoefA() |
| { |
| if ((options & A) != 0) |
| { |
| return firstCoefA; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| private void setFirstCoefA(BigInteger firstCoefA) |
| throws IllegalArgumentException |
| { |
| if ((options & A) == 0) |
| { |
| options |= A; |
| this.firstCoefA = firstCoefA; |
| } |
| else |
| { |
| throw new IllegalArgumentException("First Coef A already set"); |
| } |
| } |
| |
| public BigInteger getOrderOfBasePointR() |
| { |
| if ((options & R) != 0) |
| { |
| return orderOfBasePointR; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| private void setOrderOfBasePointR(BigInteger orderOfBasePointR) |
| throws IllegalArgumentException |
| { |
| if ((options & R) == 0) |
| { |
| options |= R; |
| this.orderOfBasePointR = orderOfBasePointR; |
| } |
| else |
| { |
| throw new IllegalArgumentException("Order of base point R already set"); |
| } |
| } |
| |
| public BigInteger getPrimeModulusP() |
| { |
| if ((options & P) != 0) |
| { |
| return primeModulusP; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| private void setPrimeModulusP(BigInteger primeModulusP) |
| { |
| if ((options & P) == 0) |
| { |
| options |= P; |
| this.primeModulusP = primeModulusP; |
| } |
| else |
| { |
| throw new IllegalArgumentException("Prime Modulus P already set"); |
| } |
| } |
| |
| public byte[] getPublicPointY() |
| { |
| if ((options & Y) != 0) |
| { |
| return Arrays.clone(publicPointY); |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| private void setPublicPointY(ASN1OctetString publicPointY) |
| throws IllegalArgumentException |
| { |
| if ((options & Y) == 0) |
| { |
| options |= Y; |
| this.publicPointY = publicPointY.getOctets(); |
| } |
| else |
| { |
| throw new IllegalArgumentException("Public Point Y already set"); |
| } |
| } |
| |
| public BigInteger getSecondCoefB() |
| { |
| if ((options & B) != 0) |
| { |
| return secondCoefB; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| private void setSecondCoefB(BigInteger secondCoefB) |
| throws IllegalArgumentException |
| { |
| if ((options & B) == 0) |
| { |
| options |= B; |
| this.secondCoefB = secondCoefB; |
| } |
| else |
| { |
| throw new IllegalArgumentException("Second Coef B already set"); |
| } |
| } |
| |
| public boolean hasParameters() |
| { |
| return primeModulusP != null; |
| } |
| |
| public ASN1EncodableVector getASN1EncodableVector(ASN1ObjectIdentifier oid, boolean publicPointOnly) |
| { |
| ASN1EncodableVector v = new ASN1EncodableVector(); |
| v.add(oid); |
| |
| if (!publicPointOnly) |
| { |
| v.add(new UnsignedInteger(0x01, getPrimeModulusP())); |
| v.add(new UnsignedInteger(0x02, getFirstCoefA())); |
| v.add(new UnsignedInteger(0x03, getSecondCoefB())); |
| v.add(new DERTaggedObject(false, 0x04, new DEROctetString(getBasePointG()))); |
| v.add(new UnsignedInteger(0x05, getOrderOfBasePointR())); |
| } |
| v.add(new DERTaggedObject(false, 0x06, new DEROctetString(getPublicPointY()))); |
| if (!publicPointOnly) |
| { |
| v.add(new UnsignedInteger(0x07, getCofactorF())); |
| } |
| |
| return v; |
| } |
| |
| public ASN1Primitive toASN1Primitive() |
| { |
| return new DERSequence(getASN1EncodableVector(usage, !hasParameters())); |
| } |
| } |