Skip to content

Commit 8ef05c1

Browse files
author
madison
committed
Enhanced Support for OAEP params and cipher names.
Updates cipher param names for OAEP use cases. Also updates how OAEP params are passed to the underlying JCE provider and creates a fallback to use no params (and rely only on the cipher name).
1 parent 8856f18 commit 8ef05c1

3 files changed

Lines changed: 148 additions & 12 deletions

File tree

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<modelVersion>4.0.0</modelVersion>
55
<artifactId>agent</artifactId>
66
<name>Direct Project Security And Trust Agent</name>
7-
<version>8.2.0-SNAPSHOT</version>
7+
<version>8.1.2-SNAPSHOT</version>
88
<description>Direct Project Security And Trust Agent</description>
99
<inceptionYear>2010</inceptionYear>
1010
<url>https://github.com/DirectProjectJavaRI/agent</url>

src/main/java/org/nhindirect/stagent/cryptography/bc/DirectJceAsymmetricKeyUnwrapper.java

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,27 @@
22

33
import java.lang.reflect.Field;
44
import java.lang.reflect.Method;
5-
import java.security.AlgorithmParameters;
65
import java.security.Key;
76
import java.security.PrivateKey;
7+
import java.security.spec.MGF1ParameterSpec;
88
import java.util.HashMap;
99
import java.util.Map;
1010

1111
import javax.crypto.Cipher;
12+
import javax.crypto.spec.OAEPParameterSpec;
13+
import javax.crypto.spec.PSource;
1214
import javax.crypto.spec.SecretKeySpec;
1315

16+
import org.bouncycastle.asn1.ASN1Encodable;
1417
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
18+
import org.bouncycastle.asn1.ASN1OctetString;
19+
import org.bouncycastle.asn1.DERSequence;
20+
import org.bouncycastle.asn1.DLSequence;
21+
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
22+
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
1523
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
24+
import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
1625
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
17-
import org.bouncycastle.operator.DefaultAlgorithmNameFinder;
1826
import org.bouncycastle.operator.GenericKey;
1927
import org.bouncycastle.operator.OperatorException;
2028
import org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
@@ -68,13 +76,63 @@ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm
6876

6977
if( this.getAlgorithmIdentifier().getAlgorithm().getId().equals(PKCSObjectIdentifiers.id_RSAES_OAEP.toString())) {
7078
// Get the SHA Digest from the algorithm identifier
71-
AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance(this.getAlgorithmIdentifier().getAlgorithm().toString());
72-
algorithmParameters.init(this.getAlgorithmIdentifier().getParameters().toASN1Primitive().getEncoded());
73-
keyCipher.init(Cipher.DECRYPT_MODE, privateKey, algorithmParameters);
79+
//AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance(this.getAlgorithmIdentifier().getAlgorithm().toString());
80+
//algorithmParameters.init(this.getAlgorithmIdentifier().getParameters().toASN1Primitive().getEncoded());
81+
ASN1Encodable asn1Encodable = this.getAlgorithmIdentifier().getParameters();
82+
83+
RSAESOAEPparams rsaesoaePparams = null;
84+
85+
if( asn1Encodable instanceof DERSequence) {
86+
DERSequence derSequence = (DERSequence) asn1Encodable;
87+
rsaesoaePparams = RSAESOAEPparams.getInstance(derSequence);
88+
}
89+
else if( asn1Encodable instanceof DLSequence) {
90+
DLSequence dlSequence = (DLSequence) asn1Encodable;
91+
rsaesoaePparams = RSAESOAEPparams.getInstance(dlSequence);
92+
}
93+
else
94+
rsaesoaePparams = RSAESOAEPparams.getInstance(asn1Encodable);
95+
96+
if (rsaesoaePparams != null) {
97+
String hashAlg = getDigestName(rsaesoaePparams.getHashAlgorithm().getAlgorithm());
98+
99+
AlgorithmIdentifier mgfAlgId = rsaesoaePparams.getMaskGenAlgorithm();
100+
String maskFunction = oidToMGFName(mgfAlgId.getAlgorithm().getId());
101+
String mgfHashAlg = getDigestName(AlgorithmIdentifier.getInstance(mgfAlgId.getParameters()).getAlgorithm());
102+
103+
AlgorithmIdentifier pSourceAlgId = rsaesoaePparams.getPSourceAlgorithm();
104+
ASN1Encodable pSrcValue = pSourceAlgId.getParameters();
105+
byte[] pValue = ASN1OctetString.getInstance(pSrcValue).getOctets();
106+
PSource.PSpecified pSource = (pValue == null) ? PSource.PSpecified.DEFAULT : new PSource.PSpecified(pValue);
107+
108+
109+
OAEPParameterSpec oaepParams = new OAEPParameterSpec(
110+
hashAlg, // main hash algorithm
111+
maskFunction, //mask function
112+
new MGF1ParameterSpec(mgfHashAlg),
113+
pSource
114+
);
115+
116+
117+
try {
118+
keyCipher.init(Cipher.DECRYPT_MODE, privateKey, oaepParams);
119+
}
120+
catch (Exception e) {
121+
// fall back to NOT supplying algorithm parameters in the event the underlying JCE provider does not support
122+
// parameters. This should work in most cases as long as the encryption algorithm string contains a
123+
// complete OAEP padding scheme such as RSA/None/OAEPWithSHA-256AndMGF1Padding.
124+
keyCipher.init(Cipher.DECRYPT_MODE, privateKey);
125+
}
126+
}
127+
else
128+
keyCipher.init(Cipher.DECRYPT_MODE, privateKey);
129+
130+
131+
74132
} else {
75133
keyCipher.init(Cipher.DECRYPT_MODE, privateKey);
76134
}
77-
byte[] var1 = keyCipher.doFinal(encryptedKey); // emm
135+
78136
sKey = new SecretKeySpec(keyCipher.doFinal(encryptedKey), encryptedKeyAlgorithm.getAlgorithm().getId());
79137
}
80138

@@ -87,5 +145,21 @@ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm
87145

88146
}
89147

148+
private String getDigestName(ASN1ObjectIdentifier oid) {
149+
if (oid.equals(OIWObjectIdentifiers.idSHA1)) return "SHA-1";
150+
if (oid.equals(NISTObjectIdentifiers.id_sha224)) return "SHA-224";
151+
if (oid.equals(NISTObjectIdentifiers.id_sha256)) return "SHA-256";
152+
if (oid.equals(NISTObjectIdentifiers.id_sha384)) return "SHA-384";
153+
if (oid.equals(NISTObjectIdentifiers.id_sha512)) return "SHA-512";
154+
throw new IllegalArgumentException("Unknown digest OID: " + oid);
155+
}
156+
157+
private String oidToMGFName(String oid) {
158+
if (oid.equals(PKCSObjectIdentifiers.id_mgf1.getId())) {
159+
return "MGF1"; // JCE name
160+
}
161+
// if we never need to support additional mask generation functions, then extend the mapping above
162+
throw new IllegalArgumentException("Unsupported MGF: " + oid);
163+
}
90164

91165
}

src/main/java/org/nhindirect/stagent/cryptography/bc/DirectNamedJcaJceExtHelper.java

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@
55
import javax.crypto.SecretKey;
66

77
import org.apache.commons.lang3.StringUtils;
8+
import org.bouncycastle.asn1.ASN1Encodable;
9+
import org.bouncycastle.asn1.DERSequence;
10+
import org.bouncycastle.asn1.DLSequence;
11+
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
12+
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
813
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
14+
import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
915
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
1016
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
1117
import org.bouncycastle.operator.SymmetricKeyUnwrapper;
@@ -26,15 +32,71 @@ public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier k
2632
retVal.setProvider(providerName);
2733

2834
/*
29-
* For a non-BC provider, we need to map the OAEP algorithm OID to a name. Many HSMs do not recognized the algorithm OID and explicitly
30-
* need the name. May need to get sophisticated in later versions to map names for specific HSMs.
35+
* Use explicit names to indicate parameters for OAEP so we don't have to pass them later
36+
* use a parameter structure (some providers may not support setting parameters via a parameters
37+
* structure).
3138
*/
32-
if (!StringUtils.isEmpty(providerName) && !providerName.equalsIgnoreCase("BC"))
39+
40+
if (PKCSObjectIdentifiers.id_RSAES_OAEP.equals(keyEncryptionAlgorithm.getAlgorithm()))
3341
{
34-
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/None/OAEPWithSHA1AndMGF1Padding");
42+
ASN1Encodable asn1Encodable = keyEncryptionAlgorithm.getParameters();
43+
44+
RSAESOAEPparams rsaesoaePparams = null;
45+
46+
if( asn1Encodable instanceof DERSequence) {
47+
DERSequence derSequence = (DERSequence) asn1Encodable;
48+
rsaesoaePparams = RSAESOAEPparams.getInstance(derSequence);
49+
}
50+
if( asn1Encodable instanceof DLSequence) {
51+
DLSequence dlSequence = (DLSequence) asn1Encodable;
52+
rsaesoaePparams = RSAESOAEPparams.getInstance(dlSequence);
53+
}
54+
55+
if (!StringUtils.isEmpty(providerName) && !providerName.equalsIgnoreCase("BC"))
56+
{
57+
// special cases for different HSMs
58+
if (providerName.equalsIgnoreCase("SAFENETPROTECTWRAPPER"))
59+
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/ECB/OAEP");
60+
else
61+
{
62+
// Default use case for LUNA
63+
if( rsaesoaePparams != null) {
64+
String algorithm = rsaesoaePparams.getHashAlgorithm().getAlgorithm().getId();
65+
if (algorithm.equals(NISTObjectIdentifiers.id_sha256.getId()))
66+
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/None/OAEPWithSHA-256AndMGF1Padding");
67+
else if (algorithm.equals(NISTObjectIdentifiers.id_sha384.getId()))
68+
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/None/OAEPWithSHA-384AndMGF1Padding");
69+
else if (algorithm.equals(NISTObjectIdentifiers.id_sha512.getId()))
70+
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/None/OAEPWithSHA-512AndMGF1Padding");
71+
else if (algorithm.equals(OIWObjectIdentifiers.idSHA1.getId()))
72+
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/None/OAEPWithSHA-1AndMGF1Padding");
73+
}
74+
else {
75+
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/None/OAEPWithSHA1AndMGF1Paddingg");
76+
}
77+
}
78+
}
79+
else {
80+
81+
if( rsaesoaePparams != null) {
82+
String algorithm = rsaesoaePparams.getHashAlgorithm().getAlgorithm().getId();
83+
if (algorithm.equals(NISTObjectIdentifiers.id_sha256.getId()))
84+
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
85+
else if (algorithm.equals(NISTObjectIdentifiers.id_sha384.getId()))
86+
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/ECB/OAEPWithSHA-384AndMGF1Padding");
87+
else if (algorithm.equals(NISTObjectIdentifiers.id_sha512.getId()))
88+
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
89+
else if (algorithm.equals(OIWObjectIdentifiers.idSHA1.getId()))
90+
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
91+
}
92+
else {
93+
retVal.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
94+
}
95+
}
96+
3597
}
3698

37-
return retVal;
99+
return retVal;
38100
}
39101

40102
public JceKTSKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey, byte[] partyUInfo, byte[] partyVInfo)

0 commit comments

Comments
 (0)