ECDH secp256k1 集成

在Android 原生api是不支持secp256k1算法的,所以要先集成以下库:

implementation 'com.madgag.spongycastle:core:1.58.0.0'
    compile 'com.madgag.spongycastle:prov:1.54.0.0'
    compile 'com.madgag.spongycastle:pkix:1.54.0.0'
    compile 'com.madgag.spongycastle:pg:1.54.0.0'

然后在使用前需要添加一行代码

static {
        Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
    }

1 获取公钥与私钥 :

private void nnnn() {

        X9ECParameters ecp = SECNamedCurves.getByName("secp256k1");

        ECDomainParameters domainParams = new ECDomainParameters(
                ecp.getCurve(),
                ecp.getG(),
                ecp.getN(),
                ecp.getH(),
                ecp.getSeed());

// Generate a private key and a public key

        AsymmetricCipherKeyPair keyPair;

        ECKeyGenerationParameters keyGenParams = new ECKeyGenerationParameters(domainParams, new SecureRandom());

        ECKeyPairGenerator generator = new ECKeyPairGenerator();

        generator.init(keyGenParams);

        keyPair = generator.generateKeyPair();

        ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate();

        ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic();

        byte[] privateKeyBytes = privateKey.getD().toByteArray();

// First print our generated private key and public key


        Log.e("mlt",".......Private key:..........."+ECDH.toHex(privateKeyBytes));


        Log.e("mlt","........Public key:..........."+ECDH.toHex(publicKey.getQ().getEncoded(true)));
// Then calculate the public key only using domainParams.getG() and private key

        ECPoint Q = domainParams.getG().multiply(new BigInteger(privateKeyBytes));

        Log.e("mlt",".......Calculated public key:...." +
                "......."+ECDH.toHex(Q.getEncoded(true)));

// The calculated public key and generated public key should always match

        if (!ECDH.toHex(publicKey.getQ().getEncoded(true)).equals(ECDH.toHex(Q.getEncoded(true)))) {

            Log.e("mlt",".......ERROR: Public keys do not match!:...........");

        } else {

            Log.e("mlt",".......Congratulations, public keys match:...........");

        }

    }

字符转byte[]

 public static String toHex(byte[] data) {

        StringBuilder sb = new StringBuilder();
        for (byte b: data) {
            sb.append(String.format("%02x", b&0xff));
        }
        return sb.toString();

    }

先看下密钥对:

//56477ec67d3e3426db2646a9f873cb6c90753bcfc51ea1fc8b0b982dffcd8791       Private key

//0384bb60ab084f42a6093839eec228d9b3f4641ff80b6fe96a1ad55ec12ade9a8f     Public key

3 生成共享密钥

public static String generateAgreedKey(PrivateKey privateKey, PublicKey publicKey) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException {
        KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", "SC");
        keyAgreement.init(privateKey);
        keyAgreement.doPhase(publicKey, true);

        byte[] sharedKeyBytes = keyAgreement.generateSecret();
//        return Base64.encodeToString(sharedKeyBytes, Base64.DEFAULT).replaceAll("\n", "");
        return toHex(sharedKeyBytes);
    }

4 因为生成对是16进制 key需要转publickey 和privatekey 还需另外方法

public static ECPublicKey keyToPublick(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
        // transform from hex to ECPublicKey
        byte[] ecRawExternalPublicKey = hexStringToByteArray(key);
        ECPublicKey ecExternalPublicKey = null;
        KeyFactory externalKeyFactor = null;

        ECNamedCurveParameterSpec ecExternalNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec("secp256k1");
        ECCurve curve = ecExternalNamedCurveParameterSpec.getCurve();
        EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, ecExternalNamedCurveParameterSpec.getSeed());
        java.security.spec.ECPoint ecPoint = ECPointUtil.decodePoint(ellipticCurve, ecRawExternalPublicKey);
        java.security.spec.ECParameterSpec ecParameterSpec = EC5Util.convertSpec(ellipticCurve, ecExternalNamedCurveParameterSpec);
        java.security.spec.ECPublicKeySpec externalPublicKeySpec = new java.security.spec.ECPublicKeySpec(ecPoint, ecParameterSpec);

        externalKeyFactor = java.security.KeyFactory.getInstance("EC");
        // this is externalPubicKey
        ecExternalPublicKey = (ECPublicKey) externalKeyFactor.generatePublic(externalPublicKeySpec);
        return ecExternalPublicKey;
    }


    public static ECPrivateKey keyToPrivate(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
        // transform from hex to ECPublicKey
        byte[] ecRawExternalPublicKey = hexStringToByteArray(key);
        ECPrivateKey ecPrivateKey = null;
        KeyFactory externalKeyFactor = null;

        ECNamedCurveParameterSpec ecExternalNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec("secp256k1");
        ECCurve curve = ecExternalNamedCurveParameterSpec.getCurve();
        EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, ecExternalNamedCurveParameterSpec.getSeed());
        java.security.spec.ECParameterSpec ecParameterSpec = EC5Util.convertSpec(ellipticCurve, ecExternalNamedCurveParameterSpec);
        java.security.spec.ECPrivateKeySpec externalPublicKeySpec = new java.security.spec.ECPrivateKeySpec(new BigInteger(ecRawExternalPublicKey), ecParameterSpec);

        externalKeyFactor = java.security.KeyFactory.getInstance("EC");
        // this is externalPubicKey
        ecPrivateKey = (ECPrivateKey) externalKeyFactor.generatePrivate(externalPublicKeySpec);
        return ecPrivateKey;
    }

string key 转 byte[]

 public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }

5 调用方法生成共享密钥

Log.e("mlt","...........aaa....."+ECDH.generateAgreedKey(globalData.getPrivateKey(), ECDH.keyToPublick(ss)));//随时生成私钥可以用这个

Log.e("mlt","...........aaa....."+ECDH.generateAgreedKey(ECDH.keyToPrivate(prsss), ECDH.keyToPublick(ss)));//把本地私钥保存本地

 public static String generateAgreedKey(PrivateKey privateKey, PublicKey publicKey) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException {
        KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", "SC");
        keyAgreement.init(privateKey);
        keyAgreement.doPhase(publicKey, true);

        byte[] sharedKeyBytes = keyAgreement.generateSecret();
//        return Base64.encodeToString(sharedKeyBytes, Base64.DEFAULT).replaceAll("\n", "");
        return toHex(sharedKeyBytes);
    }

基本就可以了,下面说几个问题,本来stringkey是用下面这两个方法,结果会出现问题

public static PublicKey stringToPublicKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
        byte[] keyBytes = Base64.decode(key.getBytes("utf-8"), Base64.DEFAULT);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("ECDH", "SC");
        return keyFactory.generatePublic(spec);
    }
public static PrivateKey stringToPrivateKey(String key) throws UnsupportedEncodingException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] keyBytes = Base64.decode(key.getBytes("utf-8"), Base64.DEFAULT);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("ECDH", "SC");
        return keyFactory.generatePrivate(spec);
    }

这个两个不成功所以采用上面的方法实现

参考代码:

// arrive a string like this 04456cb4ba8ee9263311485baa8562c27991f7ff22d59f3d8245b9a05661d159911b632a6f8a7a080d82f4ca77e4d12bb201b89c8ec93f61d5b4dd22df42e1b482
Map<String, Object> result = new HashMap<>();
    try {

        // set provider
        Security.addProvider(new BouncyCastleProvider());

        // transform from hex to ECPublicKey
        byte[] ecRawExternalPublicKey = this.toByte(externalRawPublicKey);
        ECPublicKey ecExternalPublicKey = null;
        KeyFactory externalKeyFactor = null;

        ECNamedCurveParameterSpec ecExternalNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec("secp256r1");
        ECCurve curve = ecExternalNamedCurveParameterSpec.getCurve();
        EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, ecExternalNamedCurveParameterSpec.getSeed());
        java.security.spec.ECPoint ecPoint = ECPointUtil.decodePoint(ellipticCurve, ecRawExternalPublicKey);
        java.security.spec.ECParameterSpec ecParameterSpec = EC5Util.convertSpec(ellipticCurve, ecExternalNamedCurveParameterSpec);
        java.security.spec.ECPublicKeySpec externalPublicKeySpec = new java.security.spec.ECPublicKeySpec(ecPoint, ecParameterSpec);

        externalKeyFactor = java.security.KeyFactory.getInstance("EC");
        // this is externalPubicKey
        ecExternalPublicKey = (ECPublicKey) externalKeyFactor.generatePublic(externalPublicKeySpec);

        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDH","BC");
        keyGen.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());

        KeyPair pair = keyGen.generateKeyPair();
        ECPublicKey pub = (ECPublicKey)pair.getPublic();
        ECPrivateKey pvt = (ECPrivateKey)pair.getPrivate();

        byte[] pubEncoded = pub.getEncoded();
        byte[] pvtEncoded = pvt.getEncoded();

        KeyAgreement keyAgree = KeyAgreement.getInstance("ECDH");
        keyAgree.init(pvt);
        keyAgree.doPhase(ecExternalPublicKey, true);

        System.out.println("sharedKey:"+ this.bytesToHex( keyAgree.generateSecret() ));

        // internal public key
        return"04"+ pub.getW().getAffineX().toString(16) + pub.getW().getAffineY().toString(16)

    }
    catch (Exception e ){
        e.printStackTrace();
        return null;
    }

https://www.codenong.com/51861056/

https://www.lmlphp.com/user/151226/article/item/3360735/

https://cloud.tencent.com/developer/ask/sof/275206

http://www.17bigdata.com/study/programming/bcalg/bcalg-secp256k1.html

https://blog.csdn.net/weixin_29192211/article/details/114853972

// generate bogus keypair(!) with named-curve params

KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");

ECGenParameterSpec gps = new ECGenParameterSpec ("secp256r1"); // NIST P-256

kpg.initialize(gps);

KeyPair apair = kpg.generateKeyPair();

ECPublicKey apub = (ECPublicKey)apair.getPublic();

ECParameterSpec aspec = apub.getParams();

// could serialize aspec for later use (in compatible JRE)

//

// for test only reuse bogus pubkey, for real substitute values

ECPoint apoint = apub.getW();

BigInteger x = apoint.getAffineX(), y = apoint.getAffineY();

// construct point plus params to pubkey

ECPoint bpoint = new ECPoint (x,y);

ECPublicKeySpec bpubs = new ECPublicKeySpec (bpoint, aspec);

KeyFactory kfa = KeyFactory.getInstance ("EC");

ECPublicKey bpub = (ECPublicKey) kfa.generatePublic(bpubs);

//

// for test sign with original key, verify with reconstructed key

Signature sig = Signature.getInstance ("SHA256withECDSA");

byte [] data = "test".getBytes();

sig.initSign(apair.getPrivate());

sig.update (data);

byte[] dsig = sig.sign();

sig.initVerify(bpub);

sig.update(data);

System.out.println (sig.verify(dsig));

https://blog.csdn.net/weixin_39583751/article/details/116008623

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值