android - 从字节数组生成 ECPublicKey

标签 android cryptography bouncycastle

我得到一个 64 位未压缩的公钥,需要运行 ECDH 来生成共享 key 。 为了调用 ECDH,我需要将字节数组转换为 PublicKey 并且我使用的是我在本论坛中找到的以下代码:

public static void setOtherPublicKey(byte[] publicKeyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException
{       

    try {
        //EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
        KeyFactory generator = KeyFactory.getInstance("EC");
        //PrivateKey privateKey = generator.generatePrivate(privateKeySpec);

        EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
        blePubKey = generator.generatePublic(publicKeySpec);
    } catch (Exception e) {
        throw new IllegalArgumentException("Failed to create KeyPair from provided encoded keys", e);
    }
}

此代码抛出一个 InvalidKeySpecException

例如,对方的公钥为:

9b5e9a5a971877530c9cadbbea93c2ee2483d65052678f745bad79f110173520
54019832e11376537a76c4defd0b3dfdc667a974239147f323cdcfd2baa39892

得到以下答案后添加代码:

public static void setOtherPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException
{
    // first generate key pair of your own   
    ECPublicKey pubKey = (ECPublicKey) SecPage.g_kpA.getPublic();
    ECParameterSpec params = pubKey.getParams();
    int keySizeBytes = params.getOrder().bitLength() / Byte.SIZE;

    // get the other party 64 bytes
    //byte [] otherPub = crypto.getBlePubKeyBytes();

    byte[] otherPub = hexStringToByteArray("ac2bdd28fce5c7b181b34f098b0934742281246ed907a5f646940c1edcb724e7c7358356aebea810322a8e324cc77f376df4cabd754110ad41ec178c0a6b8e5f");
    ByteArrayBuffer xBytes = new ByteArrayBuffer(33);
    ByteArrayBuffer yBytes = new ByteArrayBuffer(33);

    byte[] zero = {(byte)0x00};
    xBytes.append(zero, 0, 1);
    xBytes.append(otherPub, 0, 32);
    yBytes.append(zero, 0, 1);
    yBytes.append(otherPub, 32, 32);


    // generate the public key point    
    BigInteger x = new BigInteger(xBytes.buffer());
    BigInteger y = new BigInteger(yBytes.buffer());

    ECPoint w  = new ECPoint(x, y);

    // generate the key of the other side
    ECPublicKeySpec otherKeySpec = new ECPublicKeySpec(w  , params);
    KeyFactory keyFactory = KeyFactory.getInstance("EC");
    blePubKey = (ECPublicKey) keyFactory.generatePublic(otherKeySpec);
}

最佳答案

好吧,你知道吗,你实际上可以这样做......在评论中解释。

public class ECDHPub {

    private static ECPublicKey decodeECPublicKey(ECParameterSpec params,
            final byte[] pubkey) throws NoSuchAlgorithmException,
            InvalidKeySpecException {
        int keySizeBytes = params.getOrder().bitLength() / Byte.SIZE;

        int offset = 0;
        BigInteger x = new BigInteger(1, Arrays.copyOfRange(pubkey, offset,
                offset + keySizeBytes));
        offset += keySizeBytes;
        BigInteger y = new BigInteger(1, Arrays.copyOfRange(pubkey, offset,
                offset + keySizeBytes));
        ECPoint w = new ECPoint(x, y);

        ECPublicKeySpec otherKeySpec = new ECPublicKeySpec(w, params);
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        ECPublicKey otherKey = (ECPublicKey) keyFactory
                .generatePublic(otherKeySpec);
        return otherKey;
    }

    private static byte[] encodeECPublicKey(ECPublicKey pubKey) {
        int keyLengthBytes = pubKey.getParams().getOrder().bitLength()
                / Byte.SIZE;
        byte[] publicKeyEncoded = new byte[2 * keyLengthBytes];

        int offset = 0;

        BigInteger x = pubKey.getW().getAffineX();
        byte[] xba = x.toByteArray();
        if (xba.length > keyLengthBytes + 1 || xba.length == keyLengthBytes + 1
                && xba[0] != 0) {
            throw new IllegalStateException(
                    "X coordinate of EC public key has wrong size");
        }

        if (xba.length == keyLengthBytes + 1) {
            System.arraycopy(xba, 1, publicKeyEncoded, offset, keyLengthBytes);
        } else {
            System.arraycopy(xba, 0, publicKeyEncoded, offset + keyLengthBytes
                    - xba.length, xba.length);
        }
        offset += keyLengthBytes;

        BigInteger y = pubKey.getW().getAffineY();
        byte[] yba = y.toByteArray();
        if (yba.length > keyLengthBytes + 1 || yba.length == keyLengthBytes + 1
                && yba[0] != 0) {
            throw new IllegalStateException(
                    "Y coordinate of EC public key has wrong size");
        }

        if (yba.length == keyLengthBytes + 1) {
            System.arraycopy(yba, 1, publicKeyEncoded, offset, keyLengthBytes);
        } else {
            System.arraycopy(yba, 0, publicKeyEncoded, offset + keyLengthBytes
                    - yba.length, yba.length);
        }

        return publicKeyEncoded;
    }

    public static void main(String[] args) throws Exception {

        // (only) required for named curves other than those used in JCE
        Security.addProvider(new BouncyCastleProvider());

        // create local and remote key
        KeyPairGenerator kpgen = KeyPairGenerator.getInstance("ECDH", "BC");
        ECGenParameterSpec genspec = new ECGenParameterSpec("brainpoolp256r1");
        kpgen.initialize(genspec);
        KeyPair localKeyPair = kpgen.generateKeyPair();
        KeyPair remoteKeyPair = kpgen.generateKeyPair();

        // test generation
        byte[] encodedRemotePublicKey = encodeECPublicKey((ECPublicKey) remoteKeyPair
                .getPublic());
        // test creation
        ECPublicKey remoteKey = decodeECPublicKey(
                ((ECPublicKey) localKeyPair.getPublic()).getParams(),
                encodedRemotePublicKey);

        // local key agreement
        KeyAgreement localKA = KeyAgreement.getInstance("ECDH");
        localKA.init(localKeyPair.getPrivate());
        localKA.doPhase(remoteKey, true);
        byte[] localSecret = localKA.generateSecret();

        // remote key agreement
        KeyAgreement remoteKA = KeyAgreement.getInstance("ECDH");
        remoteKA.init(remoteKeyPair.getPrivate());
        remoteKA.doPhase((ECPublicKey) localKeyPair.getPublic(), true);
        byte[] remoteSecret = localKA.generateSecret();

        // validation
        System.out.println(Arrays.equals(localSecret, remoteSecret));
    }
}

关于android - 从字节数组生成 ECPublicKey,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25443756/

相关文章:

c++ - 无法用 BER 解码 RSA 公钥

java - 如何获取 RSAPrivateKey 的实例

c# - .NET,弹跳城堡 : How to save public Key then import it from a File?

android - 如何为 NavigationView 中的单个菜单项提供自定义文本颜色?

android - 如何以节能的方式使用 Android 接收驾驶启动和停止 Activity ,甚至可以离线工作?

android - String.format 使用逗号代替点

java - 使用 Java 中的 Bouncy CaSTLe 创建具有主题替代项的 PKCS10 请求

java - 设置每行的 Edittext 背景

ios - iOS Swift 中使用 CBC 模式的 AES 128 解密

java - ASN 1 UPER 编码器/解码器