Skip to content

Commit fb70a4a

Browse files
committed
LMSSigner and HSSSigner clear any buffered message on init() and refuse a one-shot generateSignature(byte[]) / verifySignature(byte[], byte[]) call made with a message already absorbed through update(), the refusal preceding the key read so a rejected call spends no one-time key.
1 parent b51452f commit fb70a4a

5 files changed

Lines changed: 700 additions & 1 deletion

File tree

‎core/src/main/java/org/bouncycastle/crypto/signers/HSSSigner.java‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,28 @@ public void init(boolean forSigning, CipherParameters param)
3131
{
3232
this.pubKey = (HSSPublicKeyParameters)param;
3333
}
34+
35+
reset();
3436
}
3537

38+
/**
39+
* Sign the passed in message. This is the one-shot form; it must not be mixed with the
40+
* buffered form, so a call made with data already absorbed through {@link #update(byte)} is
41+
* refused rather than silently discarding it - call {@link #reset()} first, or use
42+
* {@link #generateSignature()} to sign what was buffered.
43+
*
44+
* @param message the message to be signed.
45+
* @return the signature.
46+
* @throws IllegalStateException if a buffered message is present, or the signer is not
47+
* initialised for signing.
48+
*/
3649
public byte[] generateSignature(byte[] message)
3750
{
51+
if (buffer.size() != 0)
52+
{
53+
throw new IllegalStateException("buffered message present: call reset() or use generateSignature()");
54+
}
55+
3856
if (privKey == null)
3957
{
4058
throw new IllegalStateException("HSSSigner not initialised for signature generation");
@@ -47,8 +65,26 @@ public byte[] generateSignature(byte[] message)
4765
return privKey.generateSignature(context);
4866
}
4967

68+
/**
69+
* Verify the passed in signature against the passed in message. This is the one-shot form; it
70+
* must not be mixed with the buffered form, so a call made with data already absorbed through
71+
* {@link #update(byte)} is refused rather than silently discarding it - call
72+
* {@link #reset()} first, or use {@link #verifySignature(byte[])} to verify what was
73+
* buffered.
74+
*
75+
* @param message the message the signature is claimed to be over.
76+
* @param signature the candidate signature.
77+
* @return true if the signature verifies, false otherwise.
78+
* @throws IllegalStateException if a buffered message is present, or the signer is not
79+
* initialised for verification.
80+
*/
5081
public boolean verifySignature(byte[] message, byte[] signature)
5182
{
83+
if (buffer.size() != 0)
84+
{
85+
throw new IllegalStateException("buffered message present: call reset() or use verifySignature(byte[])");
86+
}
87+
5288
// checked before the catch-all below so a missing init is reported rather than
5389
// being folded into "signature did not verify"
5490
if (pubKey == null)

‎core/src/main/java/org/bouncycastle/crypto/signers/LMSSigner.java‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,28 @@ public void init(boolean forSigning, CipherParameters param)
7373
pubKey = (LMSPublicKeyParameters)param;
7474
}
7575
}
76+
77+
reset();
7678
}
7779

80+
/**
81+
* Sign the passed in message. This is the one-shot form; it must not be mixed with the
82+
* buffered form, so a call made with data already absorbed through {@link #update(byte)} is
83+
* refused rather than silently discarding it - call {@link #reset()} first, or use
84+
* {@link #generateSignature()} to sign what was buffered.
85+
*
86+
* @param message the message to be signed.
87+
* @return the signature.
88+
* @throws IllegalStateException if a buffered message is present, or the signer is not
89+
* initialised for signing.
90+
*/
7891
public byte[] generateSignature(byte[] message)
7992
{
93+
if (buffer.size() != 0)
94+
{
95+
throw new IllegalStateException("buffered message present: call reset() or use generateSignature()");
96+
}
97+
8098
if (privKey == null)
8199
{
82100
throw new IllegalStateException("LMSSigner not initialised for signature generation");
@@ -96,8 +114,26 @@ public byte[] generateSignature(byte[] message)
96114
return signature;
97115
}
98116

117+
/**
118+
* Verify the passed in signature against the passed in message. This is the one-shot form; it
119+
* must not be mixed with the buffered form, so a call made with data already absorbed through
120+
* {@link #update(byte)} is refused rather than silently discarding it - call
121+
* {@link #reset()} first, or use {@link #verifySignature(byte[])} to verify what was
122+
* buffered.
123+
*
124+
* @param message the message the signature is claimed to be over.
125+
* @param signature the candidate signature.
126+
* @return true if the signature verifies, false otherwise.
127+
* @throws IllegalStateException if a buffered message is present, or the signer is not
128+
* initialised for verification.
129+
*/
99130
public boolean verifySignature(byte[] message, byte[] signature)
100131
{
132+
if (buffer.size() != 0)
133+
{
134+
throw new IllegalStateException("buffered message present: call reset() or use verifySignature(byte[])");
135+
}
136+
101137
// checked before the catch-all below so a missing init is reported rather than
102138
// being folded into "signature did not verify"
103139
if (pubKey == null)

‎core/src/test/java/org/bouncycastle/crypto/signers/lms/AllTests.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public static Test suite()
1818
{
1919
TestSuite suite = new TestSuite("LMS engine tests");
2020

21+
suite.addTestSuite(BufferedMessageTests.class);
2122
suite.addTestSuite(LMOtsTests.class);
2223
suite.addTestSuite(TypeTests.class);
2324

0 commit comments

Comments
 (0)