1 package org.bouncycastle.pqc.jcajce.provider.xmss; 2 3 import java.io.IOException; 4 import java.io.ObjectInputStream; 5 import java.io.ObjectOutputStream; 6 import java.security.PublicKey; 7 8 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 9 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 10 import org.bouncycastle.crypto.CipherParameters; 11 import org.bouncycastle.pqc.crypto.util.PublicKeyFactory; 12 import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; 13 import org.bouncycastle.pqc.crypto.xmss.XMSSPublicKeyParameters; 14 import org.bouncycastle.pqc.jcajce.interfaces.XMSSKey; 15 import org.bouncycastle.util.Arrays; 16 17 public class BCXMSSPublicKey 18 implements PublicKey, XMSSKey 19 { 20 private static final long serialVersionUID = -5617456225328969766L; 21 22 private transient XMSSPublicKeyParameters keyParams; 23 private transient ASN1ObjectIdentifier treeDigest; 24 BCXMSSPublicKey( ASN1ObjectIdentifier treeDigest, XMSSPublicKeyParameters keyParams)25 public BCXMSSPublicKey( 26 ASN1ObjectIdentifier treeDigest, 27 XMSSPublicKeyParameters keyParams) 28 { 29 this.treeDigest = treeDigest; 30 this.keyParams = keyParams; 31 } 32 BCXMSSPublicKey(SubjectPublicKeyInfo keyInfo)33 public BCXMSSPublicKey(SubjectPublicKeyInfo keyInfo) 34 throws IOException 35 { 36 init(keyInfo); 37 } 38 init(SubjectPublicKeyInfo keyInfo)39 private void init(SubjectPublicKeyInfo keyInfo) 40 throws IOException 41 { 42 this.keyParams = (XMSSPublicKeyParameters)PublicKeyFactory.createKey(keyInfo); 43 this.treeDigest = DigestUtil.getDigestOID(keyParams.getTreeDigest()); 44 } 45 46 /** 47 * @return name of the algorithm - "XMSS" 48 */ getAlgorithm()49 public final String getAlgorithm() 50 { 51 return "XMSS"; 52 } 53 getEncoded()54 public byte[] getEncoded() 55 { 56 try 57 { 58 SubjectPublicKeyInfo pki = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(keyParams); 59 return pki.getEncoded(); 60 } 61 catch (IOException e) 62 { 63 return null; 64 } 65 } 66 getFormat()67 public String getFormat() 68 { 69 return "X.509"; 70 } 71 getKeyParams()72 CipherParameters getKeyParams() 73 { 74 return keyParams; 75 } 76 equals(Object o)77 public boolean equals(Object o) 78 { 79 if (o == this) 80 { 81 return true; 82 } 83 84 if (o instanceof BCXMSSPublicKey) 85 { 86 BCXMSSPublicKey otherKey = (BCXMSSPublicKey)o; 87 88 try 89 { 90 return treeDigest.equals(otherKey.treeDigest) && Arrays.areEqual(keyParams.getEncoded(), otherKey.keyParams.getEncoded()); 91 } 92 catch (IOException e) 93 { 94 return false; 95 } 96 } 97 98 return false; 99 } 100 hashCode()101 public int hashCode() 102 { 103 try 104 { 105 return treeDigest.hashCode() + 37 * Arrays.hashCode(keyParams.getEncoded()); 106 } 107 catch (IOException e) 108 { 109 // should never happen, but... 110 return treeDigest.hashCode(); 111 } 112 } 113 getHeight()114 public int getHeight() 115 { 116 return keyParams.getParameters().getHeight(); 117 } 118 getTreeDigest()119 public String getTreeDigest() 120 { 121 return DigestUtil.getXMSSDigestName(treeDigest); 122 } 123 readObject( ObjectInputStream in)124 private void readObject( 125 ObjectInputStream in) 126 throws IOException, ClassNotFoundException 127 { 128 in.defaultReadObject(); 129 130 byte[] enc = (byte[])in.readObject(); 131 132 init(SubjectPublicKeyInfo.getInstance(enc)); 133 } 134 writeObject( ObjectOutputStream out)135 private void writeObject( 136 ObjectOutputStream out) 137 throws IOException 138 { 139 out.defaultWriteObject(); 140 141 out.writeObject(this.getEncoded()); 142 } 143 } 144