1package org.bouncycastle.asn1.x509; 2 3import org.bouncycastle.asn1.ASN1Encodable; 4import org.bouncycastle.asn1.ASN1OctetString; 5import org.bouncycastle.asn1.ASN1TaggedObject; 6import org.bouncycastle.asn1.DERObject; 7import org.bouncycastle.asn1.DEROctetString; 8import org.bouncycastle.crypto.Digest; 9import org.bouncycastle.crypto.digests.SHA1Digest; 10 11/** 12 * The SubjectKeyIdentifier object. 13 * <pre> 14 * SubjectKeyIdentifier::= OCTET STRING 15 * </pre> 16 */ 17public class SubjectKeyIdentifier 18 extends ASN1Encodable 19{ 20 private byte[] keyidentifier; 21 22 public static SubjectKeyIdentifier getInstance( 23 ASN1TaggedObject obj, 24 boolean explicit) 25 { 26 return getInstance(ASN1OctetString.getInstance(obj, explicit)); 27 } 28 29 public static SubjectKeyIdentifier getInstance( 30 Object obj) 31 { 32 if (obj instanceof SubjectKeyIdentifier) 33 { 34 return (SubjectKeyIdentifier)obj; 35 } 36 37 if (obj instanceof SubjectPublicKeyInfo) 38 { 39 return new SubjectKeyIdentifier((SubjectPublicKeyInfo)obj); 40 } 41 42 if (obj instanceof ASN1OctetString) 43 { 44 return new SubjectKeyIdentifier((ASN1OctetString)obj); 45 } 46 47 if (obj instanceof X509Extension) 48 { 49 return getInstance(X509Extension.convertValueToObject((X509Extension)obj)); 50 } 51 52 throw new IllegalArgumentException("Invalid SubjectKeyIdentifier: " + obj.getClass().getName()); 53 } 54 55 public SubjectKeyIdentifier( 56 byte[] keyid) 57 { 58 this.keyidentifier=keyid; 59 } 60 61 public SubjectKeyIdentifier( 62 ASN1OctetString keyid) 63 { 64 this.keyidentifier=keyid.getOctets(); 65 } 66 67 /** 68 * Calculates the keyidentifier using a SHA1 hash over the BIT STRING 69 * from SubjectPublicKeyInfo as defined in RFC3280. 70 * 71 * @param spki the subject public key info. 72 */ 73 public SubjectKeyIdentifier( 74 SubjectPublicKeyInfo spki) 75 { 76 this.keyidentifier = getDigest(spki); 77 } 78 79 public byte[] getKeyIdentifier() 80 { 81 return keyidentifier; 82 } 83 84 public DERObject toASN1Object() 85 { 86 return new DEROctetString(keyidentifier); 87 } 88 89 /** 90 * Return a RFC 3280 type 1 key identifier. As in: 91 * <pre> 92 * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the 93 * value of the BIT STRING subjectPublicKey (excluding the tag, 94 * length, and number of unused bits). 95 * </pre> 96 * @param keyInfo the key info object containing the subjectPublicKey field. 97 * @return the key identifier. 98 */ 99 public static SubjectKeyIdentifier createSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo) 100 { 101 return new SubjectKeyIdentifier(keyInfo); 102 } 103 104 /** 105 * Return a RFC 3280 type 2 key identifier. As in: 106 * <pre> 107 * (2) The keyIdentifier is composed of a four bit type field with 108 * the value 0100 followed by the least significant 60 bits of the 109 * SHA-1 hash of the value of the BIT STRING subjectPublicKey. 110 * </pre> 111 * @param keyInfo the key info object containing the subjectPublicKey field. 112 * @return the key identifier. 113 */ 114 public static SubjectKeyIdentifier createTruncatedSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo) 115 { 116 byte[] dig = getDigest(keyInfo); 117 byte[] id = new byte[8]; 118 119 System.arraycopy(dig, dig.length - 8, id, 0, id.length); 120 121 id[0] &= 0x0f; 122 id[0] |= 0x40; 123 124 return new SubjectKeyIdentifier(id); 125 } 126 127 private static byte[] getDigest(SubjectPublicKeyInfo spki) 128 { 129 Digest digest = new SHA1Digest(); 130 byte[] resBuf = new byte[digest.getDigestSize()]; 131 132 byte[] bytes = spki.getPublicKeyData().getBytes(); 133 digest.update(bytes, 0, bytes.length); 134 digest.doFinal(resBuf, 0); 135 return resBuf; 136 } 137} 138