Created
June 20, 2018 16:18
-
-
Save shanewholloway/6ed5a52fa985b1d23024daa001b6a51e to your computer and use it in GitHub Desktop.
WebCrypto get compressed ECDH public key that is compatible with Node's ec.getPublicKey(null, 'compressed')
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const _fromCharCode = String.fromCharCode | |
export function pack_base64(arr) { | |
let res='' | |
const u8 = new Uint8Array(arr.buffer || arr) | |
const len = u8.byteLength | |
for (let i=0; i<len; i++) | |
res += _fromCharCode(u8[i]) | |
return window.btoa(res) | |
} | |
const _charCodeAt = ''.charCodeAt | |
export function unpack_base64(str_b64) { | |
const sz = window.atob(str_b64) | |
const len = sz.length | |
const res = new Uint8Array(len) | |
for (let i=0; i<len; i++) | |
res[i] = _charCodeAt.call(sz, i) | |
return res | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {pack_base64, unpack_base64} from './browser_util.jsy' | |
import ecdh_pubkey_compressed from './ecdh_pubkey_compressed.js' | |
function testWithAlg(namedCurve) { | |
const ec_alg = { name: 'ECDH', namedCurve } | |
const reexport = ecdh_raw => | |
crypto.subtle | |
.importKey('raw', ecdh_raw, ec_alg, true, []) | |
.then(ecdh => crypto.subtle.exportKey('raw', ecdh)) | |
.then(pack_base64) | |
return crypto.subtle | |
.generateKey(ec_alg, false, ['deriveKey', 'deriveBits']) | |
.then(ec => Promise.all([ | |
crypto.subtle.exportKey('raw', ec.publicKey), | |
ecdh_pubkey_compressed(ec), | |
ecdh_pubkey_compressed(ec.publicKey), | |
])) | |
.then(lst => { | |
console.log(pack_base64(lst[1])) | |
return Promise.all(lst.map(reexport)) }) | |
.then(lst => console.log(lst[0]===lst[1], lst[0]===lst[2])) | |
} | |
testWithAlg('P-256') | |
testWithAlg('P-384') | |
testWithAlg('P-521') | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default ecdh_pubkey_compressed | |
const supported_curves = { 'P-256': 1, 'P-384': 1, 'P-521': 1, } | |
export function ecdh_pubkey_compressed(ecdh) { | |
if (null != ecdh.publicKey) | |
ecdh = ecdh.publicKey | |
if (ecdh.type !== 'public' || ! ecdh.algorithm || ecdh.algorithm.name !== 'ECDH') | |
throw new TypeError('Expected a public ECDH CryptoKey') | |
if (! supported_curves[ecdh.algorithm.namedCurve] ) | |
return Promise.resolve( | |
new Error('Unsupported ECDH curve for compression') ) | |
return crypto.subtle.exportKey('raw', ecdh) | |
.then(ecdh_raw_pubkey_compressed) | |
} | |
export function ecdh_raw_pubkey_compressed(ec_raw_pubkey) { | |
const u8full = new Uint8Array(ec_raw_pubkey) | |
const len = u8full.byteLength | |
const u8 = u8full.slice(0, 1 + len >>> 1) // drop `y` | |
u8[0] = 0x2 | (u8full[len-1] & 0x01) // encode sign of `y` in first bit | |
return u8.buffer | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Based on StackOverflow answer from Adria and inspecting the byte differences between
ecdh.getPublicKey(null)
andecdh.getPublicKey(null, 'compressed')
in NodeJS.