es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Firmar datos en JAVA con secp256k1 y verificar en c ++.

Quiero firmar datos en Java y luego verificarlos en c++. Cuando firmo los datos en c++ con la biblioteca bitcoin-core/secp256k1 y luego los verifico en c++, todo funciona perfectamente. Pero cuando los firmo en Java y luego los transfiero a c++, deja de funcionar.

“`
// Creo el contexto secp256k1
secp256k1<em>context *ctx = secp256k1_context_create(SECP256K1</em>CONTEXT<em>_SIGN | SECP256K1</em>CONTEXT_VERIFY);

<pre><code> // Declaro las variables de la clave pública y la firma
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;

// Defino la longitud de la firma a 71
signature_len = 71;
// Pego la firma generada en Java
const char* signature2 = "3045022100C5C52074B7F86130D52FC6286D20E95D974D2A9457B8F39223FA571CA1419B5602203B5DA5922770EE472A2A6235B2FC07C1125763DC4C896A6561D4FD959FAA4C7D";
char signature3[72];
hex2bin(signature2, signature3);
memcpy(signature, signature3, signature_len);

// Pego la clave pública generada en Java
const char* pub_key2 = "0300F447B363996717EB807D950BC8C35C648F1AD27E98AD9E23487F4A4E7EEA2F";
char pub_key3[33];
hex2bin(pub_key2, pub_key3);
memcpy(public_key, pub_key3, 33);

// Obtengo el hash de los datos
std::string data = Vendor::sha256("BANANA");
memcpy(hash, data.c_str(), 32);

// Verifico si hay un error al analizar la clave pública
if (secp256k1_ec_pubkey_parse(ctx, &pubkey, public_key, 33) == 0) {
LOG_WNL("Error al analizar la clave pública!");
}

// Verifico si hay un error al analizar la firma
if (secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, signature_len) == 0) {
LOG_WNL("Error al analizar la firma!");
}

// Verifico la firma
int res = secp256k1_ecdsa_verify(ctx, &sig, hash, &pubkey);

return res == 1;
</code></pre>

<code>
Código en Java:
</code>
Signature dsa = Signature.getInstance("SHA256withECDSA");

<pre><code> dsa.initSign(privateKey);

String str = "BANANA";

Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");
ecdsaSign.initSign(privateKey);
ecdsaSign.update(str.getBytes("ASCII"));

byte[] signature = ecdsaSign.sign();
String sig = getHex(signature);

return sig;
</code></pre>

“`

¡Agradecería mucho una respuesta!

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El problema probablemente se debe a las diferencias en cómo se codifica la firma en Java y en C++. El código de Java está utilizando la codificación predeterminada para string.getBytes(), que es UTF-8, mientras que el código de C++ espera un formato de firma codificada DER específico.

    Para resolver el problema, debes asegurarte de que la firma esté codificada en el formato correcto en Java utilizando el mismo método que en C++. Puedes usar la biblioteca Bouncy Castle en Java para generar firmas codificadas DER.

    Aquí tienes un ejemplo de código utilizando Bouncy Castle:

    import org.bouncycastle.asn1.ASN1Sequence;
    import org.bouncycastle.asn1.DERSequenceGenerator;
    import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
    import org.bouncycastle.crypto.params.ECPublicKeyParameters;
    import org.bouncycastle.crypto.signers.ECDSASigner;
    
    import java.io.ByteArrayOutputStream;
    import java.math.BigInteger;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.Security;
    
    import static org.bouncycastle.asn1.sec.SECNamedCurves.getByName;
    
    public class ECDSA {
    
        public static void main(String[] args) throws Exception {
    
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDSA", "BC");
            keyGen.initialize(getByName("secp256k1"));
            KeyPair keyPair = keyGen.generateKeyPair();
    
            String str = "PLÁTANO"; // Cambia "BANANA" por "PLÁTANO" en el ejemplo de código original para probar la codificación UTF-8.
            byte[] message = str.getBytes("UTF-8");
    
            ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate();
            ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic();
    
            ECDSASigner signer = new ECDSASigner();
            signer.init(true, privateKey);
    
            BigInteger[] sig = signer.generateSignature(message);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DERSequenceGenerator seq = new DERSequenceGenerator(baos);
            seq.addObject(signer.getParameters().getG().getAffineXCoord().toBigInteger());
            seq.addObject(signer.getParameters().getG().getAffineYCoord().toBigInteger());
            seq.addObject(sig[0]);
            seq.addObject(sig[1]);
            seq.close();
            byte[] derSignature = baos.toByteArray();
    
            System.out.println("Firma DER:" + getHex(derSignature));
        }
    
        private static String getHex(byte[] bytes) {
            StringBuilder sb = new StringBuilder();
            for(byte b : bytes) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        }
    }
    

    Luego puedes utilizar la firma codificada DER generada en el código C++ para su verificación.

Comments are closed.