Я пытаюсь проверить подпись ECDSA, используя java, ключ был создан с помощью 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)
}
подпись происходит здесь: (сообщение было закодировано golang, используя этот метод):
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
}
здесь происходит декодирование:
//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);
однако, к сожалению, программа не работает по следующим причинам:
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 ...
Это вызывает интересную дилемму, поскольку Открытый ключ:
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEBiTlkxxYVLduJeiQ7V1AqG4bY9lxrxLX
un+qd4BeaICC1Yx/nsDvvXEPwfCYwXgnyk3u7DV3ldUiaXCIr89OoNei6D2Xgrs3
KYtpVEv7ylnUzo8xZH3/mMdLMUiy6fl8
-----END PUBLIC KEY-----
Судя по этому сайту, кажется правильным:
Ключ был сгенерирован правильно, и ASN.1 Parse правильно его декодирует. Почему Java не нравится мой код?
Кроме того, прошу прощения за плохой отступ.
Также очень неудобно печатать по одному байту в строке; рассмотрим Arrays.toString(byte[])
или шестнадцатеричный javax.xml.bind.DatatypeConverter.printHexBinary(byte[])
. И никогда (никогда) не пытайтесь преобразовать произвольные двоичные файлы, такие как криптографические подписи и другие криптообъекты, в Java String
напрямую; это отличный способ уничтожить ваши данные. И, наконец, использование ECDSA (P384) с SHA1 фактически отбрасывает большую часть вашей безопасности, но оставьте это для другого стека после того, как ваш код заработает.
Java JCE определенно не ожидает подписи в формате JSON ... поэтому json_response.getBytes("UTF-8")
заставляет меня нервничать в вашем вызове обновления.
@ lockcmpxchg8b + Формат JWS для подписи ECDSA - (base64url of) big-endian unsigned r, s фиксированной длины без метаданных, таких как теги, который является форматом, используемым PKCS11 и IINM P1363, и поддерживается Bouncy (но не SunEC) хотя по умолчанию не используется. Но JWA требует, чтобы хэш соответствовал кривой, поэтому ECDSA (P-384) требует SHA-384.
Я голосую за то, чтобы закрыть этот вопрос как не по теме, потому что без подписи на этот вопрос нельзя ответить.
Ух ты, столько ответов ты предоставил! Мне плохо сейчас приходится голосовать за закрытие. Измените вопрос и укажите необходимую информацию!
Я думаю, ваша проблема здесь:
hash := fmt.Sprintf("%x", hashBytes)
И вы должны передать hashBytes прямо в
r, s, err = ecdsa.Sign(rand.Reader, priv, hashBytes)
Bouncy Castle не жалуется на ваш открытый ключ, он жалуется на формат подписи, которую вы нам не показали. Пожалуйста, укажите байты подписи в шестнадцатеричном формате.