Skip to content

Commit 970692d

Browse files
committed
refactoring of KeyIdentifier usage, relates to github #1868
1 parent f718503 commit 970692d

18 files changed

+321
-450
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package org.bouncycastle.bcpg;
2+
3+
import java.util.List;
4+
5+
import org.bouncycastle.util.Arrays;
6+
import org.bouncycastle.util.encoders.Hex;
7+
8+
/**
9+
* Utility class for matching key-ids / fingerprints.
10+
* A {@link KeyIdentifier} can be created from either a 64-bit key-id, a fingerprint, or both.
11+
* This class was created to enable a seamless transition from use of key-ids in the API
12+
* towards identifying keys via fingerprints.
13+
*/
14+
public class KeyIdentifier
15+
{
16+
private final byte[] fingerprint;
17+
private final long keyId;
18+
19+
/**
20+
* Create a new {@link KeyIdentifier} based on a keys fingerprint.
21+
* For fingerprints matching the format of a v4, v5 or v6 key, the constructor will
22+
* try to derive the corresponding key-id from the fingerprint.
23+
*
24+
* @param fingerprint fingerprint
25+
*/
26+
public KeyIdentifier(byte[] fingerprint)
27+
{
28+
this.fingerprint = Arrays.clone(fingerprint);
29+
30+
// v4
31+
if (fingerprint.length == 20)
32+
{
33+
keyId = FingerprintUtil.keyIdFromV4Fingerprint(fingerprint);
34+
}
35+
// v5, v6
36+
else if (fingerprint.length == 32)
37+
{
38+
keyId = FingerprintUtil.keyIdFromV6Fingerprint(fingerprint);
39+
}
40+
else
41+
{
42+
keyId = 0L;
43+
}
44+
}
45+
46+
/**
47+
* Create a {@link KeyIdentifier} based on the given fingerprint and key-id.
48+
*
49+
* @param fingerprint fingerprint
50+
* @param keyId key-id
51+
*/
52+
public KeyIdentifier(byte[] fingerprint, long keyId)
53+
{
54+
this.fingerprint = Arrays.clone(fingerprint);
55+
this.keyId = keyId;
56+
}
57+
58+
/**
59+
* Create a {@link KeyIdentifier} based on the given key-id.
60+
* {@code fingerprint} will be set to {@code null}.
61+
*
62+
* @param keyId key-id
63+
*/
64+
public KeyIdentifier(long keyId)
65+
{
66+
this(null, keyId);
67+
}
68+
69+
/**
70+
* Create a wildcard {@link KeyIdentifier}.
71+
*/
72+
private KeyIdentifier()
73+
{
74+
this(new byte[0], 0L);
75+
}
76+
77+
/**
78+
* Create a wildcard {@link KeyIdentifier}.
79+
*
80+
* @return wildcard key identifier
81+
*/
82+
public static KeyIdentifier wildcard()
83+
{
84+
return new KeyIdentifier();
85+
}
86+
87+
/**
88+
* Return the fingerprint of the {@link KeyIdentifier}.
89+
* {@code fingerprint} might be null, if the {@link KeyIdentifier} was created from just a key-id.
90+
* If {@link #isWildcard()} returns true, this method returns an empty, but non-null array.
91+
*
92+
* @return fingerprint
93+
*/
94+
public byte[] getFingerprint()
95+
{
96+
return Arrays.clone(fingerprint);
97+
}
98+
99+
/**
100+
* Return the key-id of the {@link KeyIdentifier}.
101+
* This might be {@code 0L} if {@link #isWildcard()} returns true, or if an unknown
102+
* fingerprint was passed in.
103+
*
104+
* @return key-id
105+
*/
106+
public long getKeyId()
107+
{
108+
return keyId;
109+
}
110+
111+
/**
112+
* Returns true, if the {@link KeyIdentifier} specifies a wildcard (matches anything).
113+
* This is for example used with anonymous recipient key-ids / fingerprints, where the recipient
114+
* needs to try all available keys to decrypt the message.
115+
*
116+
* @return is wildcard
117+
*/
118+
public boolean isWildcard()
119+
{
120+
return keyId == 0L && fingerprint.length == 0;
121+
}
122+
123+
/**
124+
* Return true if the KeyIdentifier has a fingerprint corresponding to the passed in one.
125+
*
126+
* @param fingerprint the fingerprint to match against.
127+
* @return true if there's a match, false otherwise.
128+
*/
129+
public boolean hasFingerprint(byte[] fingerprint)
130+
{
131+
return Arrays.constantTimeAreEqual(this.fingerprint, fingerprint);
132+
}
133+
134+
/**
135+
* Return true, if this {@link KeyIdentifier} matches the given other {@link KeyIdentifier}.
136+
* This will return true if the fingerprint matches, or if the key-id matches,
137+
* or if {@link #isWildcard()} returns true.
138+
*
139+
* @param other the identifier we are matching against.
140+
* @return true if we match other, false otherwise.
141+
*/
142+
public boolean matches(KeyIdentifier other)
143+
{
144+
if (isWildcard() || other.isWildcard())
145+
{
146+
return true;
147+
}
148+
149+
if (fingerprint != null)
150+
{
151+
return Arrays.constantTimeAreEqual(fingerprint, other.fingerprint);
152+
}
153+
else
154+
{
155+
return keyId == other.keyId;
156+
}
157+
}
158+
159+
/**
160+
* Return true, if this {@link KeyIdentifier} is present in the given list of {@link KeyIdentifier} .
161+
* This will return true if a fingerprint matches, or if a key-id matches,
162+
* or if {@link #isWildcard()} returns true.
163+
*
164+
* @param others the list of key identifiers to check.
165+
* @return true, if the identifier is present in the list, false otherwise.
166+
*/
167+
public boolean isPresentIn(List<KeyIdentifier> others)
168+
{
169+
for (KeyIdentifier other: others)
170+
{
171+
if (this.matches(other))
172+
{
173+
return true;
174+
}
175+
}
176+
177+
return false;
178+
}
179+
180+
public String toString()
181+
{
182+
if (isWildcard())
183+
{
184+
return "*";
185+
}
186+
187+
if (getFingerprint() == null)
188+
{
189+
return "" + keyId;
190+
}
191+
192+
// -DM Hex.toHexString
193+
return Hex.toHexString(fingerprint).toUpperCase();
194+
}
195+
}

pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import java.io.IOException;
55
import java.util.Date;
66

7+
import org.bouncycastle.util.Pack;
8+
79
/**
810
* Base class for OpenPGP public (primary) keys.
911
* The public key packet holds the public parameters of an OpenPGP key pair.
@@ -359,4 +361,24 @@ public void encode(
359361
{
360362
out.writePacket(hasNewPacketFormat(), getPacketTag(), getEncodedContents());
361363
}
364+
365+
public static long getKeyID(PublicKeyPacket publicPk, byte[] fingerprint)
366+
{
367+
if (publicPk.version <= PublicKeyPacket.VERSION_3)
368+
{
369+
RSAPublicBCPGKey rK = (RSAPublicBCPGKey)publicPk.key;
370+
371+
return rK.getModulus().longValue();
372+
}
373+
else if (publicPk.version == PublicKeyPacket.VERSION_4)
374+
{
375+
return Pack.bigEndianToLong(fingerprint, fingerprint.length - 8);
376+
}
377+
else if (publicPk.version == PublicKeyPacket.LIBREPGP_5 || publicPk.version == PublicKeyPacket.VERSION_6)
378+
{
379+
return Pack.bigEndianToLong(fingerprint, 0);
380+
}
381+
382+
return 0;
383+
}
362384
}

pg/src/main/java/org/bouncycastle/bcpg/sig/IntendedRecipientFingerprint.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package org.bouncycastle.bcpg.sig;
22

3+
import org.bouncycastle.bcpg.KeyIdentifier;
34
import org.bouncycastle.bcpg.SignatureSubpacket;
45
import org.bouncycastle.bcpg.SignatureSubpacketTags;
5-
import org.bouncycastle.openpgp.KeyIdentifier;
66
import org.bouncycastle.util.Arrays;
77

88
/**

pg/src/main/java/org/bouncycastle/bcpg/sig/IssuerFingerprint.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package org.bouncycastle.bcpg.sig;
22

33
import org.bouncycastle.bcpg.FingerprintUtil;
4+
import org.bouncycastle.bcpg.KeyIdentifier;
45
import org.bouncycastle.bcpg.PublicKeyPacket;
56
import org.bouncycastle.bcpg.SignatureSubpacket;
67
import org.bouncycastle.bcpg.SignatureSubpacketTags;
7-
import org.bouncycastle.openpgp.KeyIdentifier;
88
import org.bouncycastle.util.Arrays;
99

1010
/**

pg/src/main/java/org/bouncycastle/bcpg/sig/IssuerKeyID.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package org.bouncycastle.bcpg.sig;
22

33
import org.bouncycastle.bcpg.FingerprintUtil;
4+
import org.bouncycastle.bcpg.KeyIdentifier;
45
import org.bouncycastle.bcpg.SignatureSubpacket;
56
import org.bouncycastle.bcpg.SignatureSubpacketTags;
6-
import org.bouncycastle.openpgp.KeyIdentifier;
77

88
/**
99
* Signature Subpacket containing the key-id of the issuers signing (sub-) key.

pg/src/main/java/org/bouncycastle/bcpg/sig/RevocationKey.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package org.bouncycastle.bcpg.sig;
22

3+
import org.bouncycastle.bcpg.KeyIdentifier;
34
import org.bouncycastle.bcpg.SignatureSubpacket;
45
import org.bouncycastle.bcpg.SignatureSubpacketTags;
5-
import org.bouncycastle.openpgp.KeyIdentifier;
66

77
/**
88
* Represents revocation key OpenPGP signature sub packet.

0 commit comments

Comments
 (0)