I am trying to sign a byte stream which does not change with a private key that does not change either, using the SHAwithECDSA. This should produce the same result, no matter how often you run the code. However, I experience some randomness which I can't explain as the resulting output changes with every run.
Here is what I do (minimal example):
public byte[] sign() {
Signature ecdsa = Signature.getInstance("SHA256withECDSA", "SunEC");
// This is a hexadecimal byte sequence I need to sign
String dataToBeSigned = "808112B43A3A381D1797BBBBBB973B99" +
"9737B93397AA2917B1B0B737B734B1B0" +
"B616B2BC3497A1AB43A3A381D1797BBB" +
"BBB973B999737B933979918181897981" +
"A17BC36B63239B4B396B6B7B93291B2B" +
"1B239B096B9B430991A9B22062349443" +
"1025687474703A2F2F7777772E77332E" +
"6F72672F54522F63616E6F6E6963616C" +
"2D6578692F4852D0E8E8E0745E5EEEEE" +
"EE5CEE665CDEE4CE5E646060625E6068" +
"5EF0DAD8CADCC646E6D0C2646A6C841A" +
"36BC07A00CB7DCAD662F3088A60A3D6A" +
"99431F81C122C2E9F1678EF531E95523" +
"70";
String hexPrivKey = "B9134963F51C4414738435057F97BBF1" +
"010CABCB8DBDE9C5D48138396AA94B9D";
byte[] privKey = DatatypeConverter.parseHexBinary(hexPrivKey);
ecdsa.initSign(getPrivateKey(privKey));
ecdsa.update(dataToBeSigned);
byte[] signature = ecdsa.sign();
System.out.println("Signature: " + DatatypeConverter.printHexBinary(signature));
}
public ECPrivateKey getPrivateKey(byte[] privateKeyBytes) {
try {
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
parameters.init(new ECGenParameterSpec("secp256r1"));
ECParameterSpec ecParameterSpec = parameters.getParameterSpec(ECParameterSpec.class);
ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(new BigInteger(privateKeyBytes), ecParameterSpec);
ECPrivateKey privateKey = (ECPrivateKey) KeyFactory.getInstance("EC").generatePrivate(ecPrivateKeySpec);
return privateKey;
} catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidParameterSpecException e) {
System.out.println(e.getClass().getSimpleName() + " occurred when trying to get private key from raw bytes", e);
return null;
}
}
Do you have any hint why this would not result in the same signature output every time I run this code? A similar question was raised here, but no real answer has been found yet.
Another question related to that: I see that there is another initSign method provided by the Signature class: initSign(PrivateKey privateKey, SecureRandom random) Why would I wanna insert a random source/seed when creating a signature? How is the receiving side supposed to verify that signature then if the random seed is not known?
Thanks for any valuable input! Marc
The specification of the algorithm explains it:
One characteristic of DSA and ECDSA is that they need to produce, for each signature generation, a fresh random value (hereafter designated as k). For effective security, k must be chosen randomly and uniformly from a set of modular integers, using a cryptographically secure process. Even slight biases in that process may be turned into attacks on the signature schemes.
So what you're seeing is perfectly normal. Of course, the designers of the algorithms made it possible for the receiver to verify the signature, otherwise it would be pointless. That's what your test should verify.