I am trying to implement RSA-OAEP encryption using Java. I understand that this requires a label which is by default an empty string. How do I change the value of label and provide a value of my choice using the built in class?
-
1Please, please, don't touch the label. You will giving yourself a compatibility/interoperability nightmare. – President James K. Polk Dec 26 '19 at 14:38
-
@JamesReinstateMonicaPolk So are you suggesting to use the default PSource.PSpecified.DEFAULT ? – akn Dec 27 '19 at 06:02
-
1Yes, if you need to use the `OAEPParameterSpec` then use `PSource.PSpecified.DEFAULT` for the `PSource`. – President James K. Polk Dec 27 '19 at 12:10
-
1The entire label hashing aspect of OAEP seems like a big mistake to me. I've never seen it used and it introduces some ambiguity which has already resulted in an incompatibility between the Oracle and Bouncycastle providers. – President James K. Polk Dec 27 '19 at 12:13
-
1@JamesReinstateMonicaPolk Can you provide a reference with regard to the problem of using labels for Bouncy Castle & Oracle providers? – Maarten Bodewes Dec 27 '19 at 18:48
-
1I feel like I had to sort this out myself a while back to support some standardized scheme, but I can't remember where. Can you say why you want to do this? – erickson Dec 27 '19 at 19:15
-
@Maarten-reinstateMonica Thanks Maarten, that question was for the OP. I was wondering if there is a specification out there that uses the "label" for some purpose. I've experimented with a specified source before, but can't remember if, like you, it was just for "fun", or if there was something in a standard that required it. – erickson Dec 27 '19 at 21:31
-
1@Maarten-reinstateMonica: When you specify `OAEPWithSHA-256AndMGF1Padding`, the Oracle provider gives you SHA256 for the label hashing alg and SHA1 for the MGF1 hash alg. Bouncycastle gives you SHA256 for both. If there were no label to hash there would be no need to specify two hash algorithms. – President James K. Polk Dec 27 '19 at 22:08
-
1@Maarten-reinstateMonica: Here is one of my answers (that references two of yours!) [https://stackoverflow.com/a/50299291/238704](https://stackoverflow.com/a/50299291/238704) – President James K. Polk Dec 27 '19 at 22:17
-
1@JamesReinstateMonicaPolk Ah, OK, that one :) Yes, Bouncy is at fault there as MGF1 defaults to SHA-1 in PKCS#1 so it should keep using that *unless* specified otherwise - and the hash algorithms *are* specified separately, for better or worse. Yeah, I just upvoted that one, can't do that again, well worded, fully agree... – Maarten Bodewes Dec 27 '19 at 22:18
-
@Maarten-reinstateMonica: Careful, PKCS#1 is not the *only* relevant standard. It may not have even been the first one to specify OAEP. There is also ANSI X9.44, IEEE P1363, and even NIST SP-56B. I have no idea what the Bouncycastle folks were using for guidance. – President James K. Polk Dec 27 '19 at 22:44
1 Answers
As I suggested in the comments, you need to use the PSource.PSpecified
constructor.
The choice of words and especially the variable P
which does not exists in the PKCS#1 specifications anywhere leads the user into a quagmire of terms in the world of ASN.1 specifications, not the place where you want to be.
I've concluded that the Java designers / devs meant id-pSpecified
where P
is then the EncodedParameters
, which is the old world for the term "label". That in turn would mean that the constructor PSource.PSpecified
can be used to indicate the (character-encoded) label. So although the term "label" could possibly indicate a string, it doesn't in the world of cryptography; you will have to perform some kind of character conversion yourself, and this character encoding should be documented if you'd were to use a textual label.
// generate a relatively small key for testing
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.generateKeyPair();
// OAEP spec with label
OAEPParameterSpec spec = new OAEPParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1,
new PSource.PSpecified("label".getBytes(US_ASCII)));
// OAEP spec without label
OAEPParameterSpec specEmpty = new OAEPParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1,
PSource.PSpecified.DEFAULT);
byte[] ct;
{
// encrypt to ciphertext using label
Cipher rsaOAEPEnc = Cipher.getInstance("RSA/ECB/OAEPPadding");
rsaOAEPEnc.init(Cipher.ENCRYPT_MODE, kp.getPublic(), spec);
ct = rsaOAEPEnc.doFinal("owlstead".getBytes(US_ASCII));
}
{
// decrypt with label
Cipher rsaOAEPDec = Cipher.getInstance("RSA/ECB/OAEPPadding");
rsaOAEPDec.init(Cipher.DECRYPT_MODE, kp.getPrivate(), spec);
byte[] pt = rsaOAEPDec.doFinal(ct);
System.out.println(new String(pt, US_ASCII));
}
{
// decrypt without label (fails with an exception)
Cipher rsaOAEPDec = Cipher.getInstance("RSA/ECB/OAEPPadding");
rsaOAEPDec.init(Cipher.DECRYPT_MODE, kp.getPrivate(), specEmpty);
byte[] pt = rsaOAEPDec.doFinal(ct);
System.out.println(new String(pt, US_ASCII));
}
By the way, above of course uses import static StandardCharsets.US_ASCII;
in case your IDE doesn't know how to find that.
Note that PKCS#1 only seems to allow empty (octet) strings as label, other use it outside the scope of PKCS#1 v2.2:
encryption operations of RSAES-OAEP take the value of a label
L
as input. In this version of PKCS #1,L
is the empty string; other uses of the label are outside the scope of this document.
So using any L
other than the empty string places you outside standard use of OAEP and you'll have to explicitly define such usages yourself. If you have some kind of identifier you might be better encoding it into the plaintext message, as libraries may not provide support for labels other than the empty string.
Finally, some nitty-gritty on how the terms are used and the actual ASN.1 definions:
pSourceAlgorithm
identifies the source (and possibly the value) of the labelL
. It SHALL be an algorithm ID with an OID in the setPKCS1PSourceAlgorithms
, which for this version SHALL consist ofid-pSpecified
, indicating that the label is specified explicitly. The parameters field associated withid-pSpecified
SHALL have a value of typeOCTET STRING
, containing the label. In previous versions of this specification, the term "encoding parameters" was used rather than "label", hence the name of the type below.
PSourceAlgorithm ::= AlgorithmIdentifier {
{PKCS1PSourceAlgorithms}
}
PKCS1PSourceAlgorithms ALGORITHM-IDENTIFIER ::= {
{ OID id-pSpecified PARAMETERS EncodingParameters },
... -- Allows for future expansion --
}
id-pSpecified OBJECT IDENTIFIER ::= { pkcs-1 9 }
EncodingParameters ::= OCTET STRING(SIZE(0..MAX))
This largely explains how the Java specifications came to be. They actually make a lot of sense if you regard them after reading the specification - except for referring to P
as separate variable within the specification of course.

- 1
- 1

- 90,524
- 13
- 150
- 263