Javascript - Java ECDH
在我的场景中,有爱丽丝(Alice)和鲍勃(Bob)同意使用哪种曲线。
- 爱丽丝生成公钥和私钥
- 爱丽丝将公钥发送给鲍勃
- Bob会生成他的密钥,并根据收到的Alice公钥来生成会话密钥(或私钥或共享密钥)。
我的问题是Alice的公钥实际上是一个点,因此它具有xy格式。
我需要将x,y坐标字节转换为ECPublicKey。
这是我正在使用的源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // outerPublicKey is the raw bytes from x,y coordinates in hex format KeyFactory kf = KeyFactory.getInstance("EC"); PublicKey remoteAlicePub = kf.generatePublic(new X509EncodedKeySpec(outerPublicKey)); KeyPairGenerator bobKeyGen = KeyPairGenerator.getInstance("ECDH","BC"); bobKeyGen.initialize(new ECGenParameterSpec(properties.getCurveName()), new SecureRandom()); KeyPair bobPair = bobKeyGen.generateKeyPair(); ECPublicKey bobPub = (ECPublicKey)bobPair.getPublic(); ECPrivateKey bobPvt = (ECPrivateKey)bobPair.getPrivate(); byte[] bobPubEncoded = bobPub.getEncoded(); byte[] bobPvtEncoded = bobPvt.getEncoded(); KeyAgreement bobKeyAgree = KeyAgreement.getInstance("ECDH"); bobKeyAgree.init(bobPvt); bobKeyAgree.doPhase(remoteAlicePub, true); return DatatypeConverter.printHexBinary(bobKeyAgree.generateSecret()); |
问题是:
1 |
如何从该点的xy坐标创建公钥?
因为
我以这种方式解决了(Java服务器端)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | // 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; } |
Javascript(客户端)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | ecdhHandShake() { let _this = this; this.keyGeneration() .then( k => { ajax({ url:"http://localhost:5050/test/ecdh/handshake", headers: { "Content-Type":"application/json" }, body: { publickey: this.buf2Hex(this.publicKey) }, method: 'POST', crossDomain: true, responseType: 'json' }) .subscribe( payload => { const publicKey = _this.hex2Arr(payload.response.publicKey); _this.serverPublicKey = _this.hex2Arr(payload.response.publicKey); _this.importServerKey() .then(sharedSecret => { const sharedSecretHex = this.buf2Hex(sharedSecret); console.log("shared key:"+ sharedSecretHex); }) .catch( e => { console.log(e); }) }, error => { console.log(error); }, () => console.log('done') ) ; }) .catch( e => { console.log(e); }) ; } keyGeneration() { let _this = this; return window.crypto.subtle.generateKey( { name:"ECDH", namedCurve:"P-256", // the curve name }, true, // <== Here if you want it to be exportable !! ["deriveKey","deriveBits"] // usage ) .then(key => { _this.keys = key; return window.crypto.subtle.exportKey( "raw", //can be"jwk" (public or private),"raw" (public only),"spki" (public only), or"pkcs8" (private only) _this.keys.publicKey ) .then(rawPublicKey => { _this.publicKey = rawPublicKey; return rawPublicKey; }) .catch(function(err){ console.error(err); }) ; }) .catch(function(err){ console.error(err); }) ; } importServerKey() { return window.crypto.subtle.importKey( 'raw', this.serverPublicKey, { name: 'ECDH', namedCurve: 'P-256' }, true, [] ) .then(aliceKeyImported => { return window.crypto.subtle.deriveBits( { name: 'ECDH', namedCurve: 'P-256', public: aliceKeyImported }, this.keys.privateKey, 256) }) .catch( e => { console.log(e); }) } hex2Arr( str ) { if (!str) { return new Uint8Array(); } const arr = []; for (let i = 0, len = str.length; i < len; i+=2) { arr.push(parseInt(str.substr(i, 2), 16)); } return new Uint8Array(arr); } buf2Hex( buf ) { return Array.from(new Uint8Array(buf)) .map(x => ('00' + x.toString(16)).slice(-2)) .join('') } |