OpenCryptoProject / JCMathLib

Implementation of mathematical operations with big numbers and elliptic curve points for smart cards with JavaCard platform.
MIT License
84 stars 28 forks source link

Help getting the public key #7

Closed ricardovf closed 5 years ago

ricardovf commented 6 years ago

Hi!

I have this code that gets a private key generated on the Secp256k1 curve and returns a 65 byte public key. Can you help me convert it to use JCMathLib? Thanks!

KeyAgreement keyAgreement = com.licel.jcardsim.crypto.KeyAgreementImpl.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN_XY, false);

public boolean getUncompressedPublicPoint(byte[] privateKey,
                                              short privateKeyOffset, byte[] publicPoint, short publicPointOffset) {
if (ecAlgorithm != KeyBuilder.TYPE_EC_FP_PRIVATE) {
                    Secp256k1.setCommonCurveParameters(this.privateKey);
                }
                this.privateKey.setS(privateKey, privateKeyOffset, (short)32);
                keyAgreement.init(this.privateKey);
                keyAgreement.generateSecret(Secp256k1.SECP256K1_G, (short)0, (short)Secp256k1.SECP256K1_G.length, publicPoint, publicPointOffset);
}

import javacard.security.ECKey;

public class Secp256k1 {

    // Nice SECp256k1 constants, only available during NIST opening hours

    protected static final byte SECP256K1_FP[] = {
        (byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
        (byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
        (byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
        (byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFE,(byte)0xFF,(byte)0xFF,(byte)0xFC,(byte)0x2F 
    };    
    protected static final byte SECP256K1_A[] = {
        (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00, 
        (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
        (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
        (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00  
    };
    protected static final byte SECP256K1_B[] = {
        (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00, 
        (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
        (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
        (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x07  
    };
    protected static final byte SECP256K1_G[] = {
        (byte)0x04, (byte)0x79,(byte)0xBE,(byte)0x66,(byte)0x7E,(byte)0xF9,(byte)0xDC,(byte)0xBB,(byte)0xAC,
        (byte)0x55,(byte)0xA0,(byte)0x62,(byte)0x95,(byte)0xCE,(byte)0x87,(byte)0x0B,(byte)0x07,
        (byte)0x02,(byte)0x9B,(byte)0xFC,(byte)0xDB,(byte)0x2D,(byte)0xCE,(byte)0x28,(byte)0xD9,
        (byte)0x59,(byte)0xF2,(byte)0x81,(byte)0x5B,(byte)0x16,(byte)0xF8,(byte)0x17,(byte)0x98,
        (byte)0x48,(byte)0x3A,(byte)0xDA,(byte)0x77,(byte)0x26,(byte)0xA3,(byte)0xC4,(byte)0x65,
        (byte)0x5D,(byte)0xA4,(byte)0xFB,(byte)0xFC,(byte)0x0E,(byte)0x11,(byte)0x08,(byte)0xA8,
        (byte)0xFD,(byte)0x17,(byte)0xB4,(byte)0x48,(byte)0xA6,(byte)0x85,(byte)0x54,(byte)0x19,
        (byte)0x9C,(byte)0x47,(byte)0xD0,(byte)0x8F,(byte)0xFB,(byte)0x10,(byte)0xD4,(byte)0xB8  
    };
    protected static final byte SECP256K1_R[] = {
        (byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
        (byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFE,
        (byte)0xBA,(byte)0xAE,(byte)0xDC,(byte)0xE6,(byte)0xAF,(byte)0x48,(byte)0xA0,(byte)0x3B,
        (byte)0xBF,(byte)0xD2,(byte)0x5E,(byte)0x8C,(byte)0xD0,(byte)0x36,(byte)0x41,(byte)0x41
    };
    protected static final byte SECP256K1_K = (byte)0x01;

    protected static boolean setCommonCurveParameters(ECKey key) {
        try {
            key.setA(SECP256K1_A, (short)0, (short)SECP256K1_A.length);
            key.setB(SECP256K1_B, (short)0, (short)SECP256K1_B.length);
            key.setFieldFP(SECP256K1_FP, (short)0, (short)SECP256K1_FP.length);
            key.setG(SECP256K1_G, (short)0, (short)SECP256K1_G.length);
            key.setR(SECP256K1_R, (short)0, (short)SECP256K1_R.length);
            key.setK(SECP256K1_K);
            return true;
        }
        catch(Exception e) {
            return false;
        }
    }
}
ricardovf commented 6 years ago

What i did so far:

        // Pre-allocate all helper structures
        ecc = new jcmathlib.ECConfig((short) 256);
        // Pre-allocate standard Secp256k1 curve and two EC points on this curve
        curve = new jcmathlib.ECCurve(true, Secp256k1.SECP256K1_FP, Secp256k1.SECP256K1_A, Secp256k1.SECP256K1_B, Secp256k1.SECP256K1_G, Secp256k1.SECP256K1_R);
        point1 = new jcmathlib.ECPoint(curve, ecc.ech);

                point1.setW(Secp256k1.SECP256K1_G, (short)0, (short) Secp256k1.SECP256K1_G.length);
                point1.multiplication(privateKey, privateKeyOffset, (short)32);
                point1.getX(publicPoint, publicPointOffset);
                point1.getY(publicPoint, (short)(publicPointOffset + curve.COORD_SIZE));
                // Add 0x04 to the start of the public key
                Util.arrayFillNonAtomic(publicPoint, publicPointOffset, (short)1, (byte)0x04);

I am getting: java.lang.ArrayIndexOutOfBoundsException, seems to happen on ech.fnc_multiplication_y1.sqrt_FP(this.theCurve.pBN); inside multiplication method...

petrs commented 6 years ago

Hi, I'm traveling right now, but will take a look on this next week - I hope it is not too late for you. Thank you for the key causing the crash - shall be easy to debug with it.

You may try to call ECConfig.setECC384Config() as quick test - this call will increase the size of internal arrays to accomodate larger 384b curves - if this will help, we are somewhere optimizing too much wrt internal buffers for intermediate values.

ricardovf commented 6 years ago

Thanks for the attention petrs! I will wait for you help next week. Im working on a bitcoin wallet for my graduation final paper. Im waiting to receive a new NPX card, with support to ALG_ECDSA_SHA_256 (to sign) and ALG_EC_SVDP_DH_PLAIN_XY (to generate the public key based on the private key). For now i am using the https://github.com/licel/jcardsim and started to test your lib, but need some help navigating it.

petrs commented 5 years ago

jcardsim is fine, I'm also testing with it and jcmathlib code conatins some checking to detect and behave slightly differently whem executed by simulator (as simulator differs from real card in some cases)

Can you also post the whole code how you are using privateKey and publicPoint so I can fully replicate?

petrs commented 5 years ago

Hi Ricardo, have you managed to solve this issue?

ricardovf commented 5 years ago

I ended using another approach generating part of what I needed outside the card. Not so secure but enough to finish my paper. You can close this now, thanks for the help.