4

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

Marc
  • 105
  • 2
  • 11

1 Answers1

4

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.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Aha, OK. Thanks for the hint to the RFC. I just couldn't imagine how a random key within ECDSA would it make possible for the other side to verify, but I guess I just need to rely on that and read the RFC to understand how. Anyway, now I know that the result perfectly normal. – Marc Jul 08 '17 at 05:48
  • No, it would be nice to be able to set a random seed after which we can set that seed in the future with the same private key to get the same signature. – devssh Apr 26 '18 at 19:44
  • Actually my intention for this is to store a long seed so that I can generate countless keys predictably and repeatedly in the future, like wallets do. – devssh Apr 26 '18 at 19:50