-1

I'm trying to verify a ECDSA signature, using java, the key was created using golang:

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"reflect"
)

func doit(){
privateKey, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
publicKey := &privateKey.PublicKey

if !elliptic.P384().IsOnCurve(publicKey.X, publicKey.Y) {
    fmt.Printf(" public key invalid. ")
}

encPriv, encPub := encode(privateKey, publicKey)

fmt.Println(encPriv)
fmt.Println(encPub)
}

the signature happens here: (message was encoded by golang, using this method):

func SignMessage(message []byte) (r *big.Int, s *big.Int, err error) {
zero := big.NewInt(0)
// Hash message:
h := sha1.New()
io.WriteString(h, string(message))
hashBytes := h.Sum(nil)
hash := fmt.Sprintf("%x", hashBytes)

// hash message
// get private key from disk:
pemEncoded, err := ioutil.ReadFile("./ecc/eccpriv.pem")
if err != nil {
    return zero, zero, err
}
pemEncodedPub, err := ioutil.ReadFile("./ecc/eccpub.pem")
if err != nil {
    return zero, zero, err
}

var priv *ecdsa.PrivateKey
//var _pub *ecdsa.PublicKey
priv, _, err = ECCDecodeFromPem(pemEncoded, pemEncodedPub)
if err != nil {
    return zero, zero, err
}

r, s, err = ecdsa.Sign(rand.Reader, priv, []byte(hash))
if err != nil {
    return zero, zero, err
}

return r, s, nil

}

the decoding aspect is happening here:

        //Verify Response
        String signature = ac.getECCDSAPublicKeyFromServer();
        String cleanSignature = ac.cleanBytes(signature);
        byte[] bSignature = Base64.getDecoder().decode(cleanSignature);

        System.out.println(cleanSignature);
        PublicKey ecdsaPublicKey = ac.getPemPublicKeyFromString(signature,"ECDSA");

        //PublicKey ecdsaPublicKey = ac.getECDSAKeyFromBytes(cleanSignature.getBytes("UTF-8"));

        Signature ecdsaVerify = Signature.getInstance("ECDSA", "BC");
        ecdsaVerify.initVerify(ecdsaPublicKey);
        ecdsaVerify.update(json_response.getBytes("UTF-8"));
        System.out.println("SIG:");
        for(int i=0;i<bSignature.length;i++){
            System.out.println(bSignature[i]);
        }
        System.out.println(new String(bSignature, StandardCharsets.UTF_8));
        System.out.println("/SIG");

        boolean result = ecdsaVerify.verify(bSignature);
        System.out.println("Result is:"+result);

however, unfortunately, the program fails because:

 Exception in thread "main" java.security.SignatureException: error decoding signature bytes.
 at org.bouncycastle.jcajce.provider.asymmetric.util.DSABase.engineVerify(Unknown Source)
 at java.base/java.security.Signature$Delegate.engineVerify(Signature.java:1245)
 at java.base/java.security.Signature.verify(Signature.java:674)
 at ...

This causes an interesting dilema, since the Public key:

-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEBiTlkxxYVLduJeiQ7V1AqG4bY9lxrxLX
un+qd4BeaICC1Yx/nsDvvXEPwfCYwXgnyk3u7DV3ldUiaXCIr89OoNei6D2Xgrs3
KYtpVEv7ylnUzo8xZH3/mMdLMUiy6fl8
-----END PUBLIC KEY-----

Seems to be correct, according to this website:

https://lapo.it/asn1js/#3076301006072A8648CE3D020106052B81040022036200040624E5931C5854B76E25E890ED5D40A86E1B63D971AF12D7BA7FAA77805E688082D58C7F9EC0EFBD710FC1F098C17827CA4DEEEC357795D522697088AFCF4EA0D7A2E83D9782BB37298B69544BFBCA59D4CE8F31647DFF98C74B3148B2E9F97C

the Key was generated correctly, and the ASN.1 Parse decodes it correctly. Why doesn't java like my code?

Also, please pardon my poor indentation.

Felipe Valdes
  • 1,998
  • 15
  • 26
  • 2
    Bouncy Castle doesn't complain about your public key, it complains about the format of the signature, which you haven't shown to us. Please include the bytes of the signature, in hexadecimals. – Maarten Bodewes Aug 04 '18 at 20:06
  • Also printing one byte per line is very clunky; consider `Arrays.toString(byte[])` or for hex `javax.xml.bind.DatatypeConverter.printHexBinary(byte[])`. And don't (ever) try to convert arbitrary binary, like crypto signatures and other crypto objects, to Java `String` directly; that's an excellent way to destroy your data. And finally using ECDSA(P384) with SHA1 is effectively throwing away most of your security -- but leave that for another Stack after you get your code working. – dave_thompson_085 Aug 04 '18 at 21:12
  • Java JCE will definitely not be expecting a JSON formatted signature...so `json_response.getBytes("UTF-8")` makes me nervous in your update call. – lockcmpxchg8b Aug 04 '18 at 22:53
  • @lockcmpxchg8b+ JWS format for ECDSA signature is (base64url of) fixed-length big-endian unsigned r,s with no metadata such as tags, which is the format used by PKCS11 and IINM P1363, and is supported by Bouncy (but not SunEC) though not used by default. But JWA requires the hash match the curve, so ECDSA(P-384) requires SHA-384. – dave_thompson_085 Aug 06 '18 at 00:27
  • I'm voting to close this question as off-topic because without the signature this question cannot be answered. – Maarten Bodewes Aug 08 '18 at 00:15
  • Wow, that's a lot of answers you've provided! I'm feeling bad now having to vote to close. Please edit the question and provide the required info! – Maarten Bodewes Aug 08 '18 at 00:23

1 Answers1

1

I think your problem is here:

hash := fmt.Sprintf("%x", hashBytes)

And you have to pass hashBytes directly to

r, s, err = ecdsa.Sign(rand.Reader, priv, hashBytes)
Maxim
  • 514
  • 2
  • 7