@@ -11,7 +11,6 @@ import enums from '../../../enums';
1111import util from '../../../util' ;
1212import computeHKDF from '../../hkdf' ;
1313import { getCipherParams } from '../../cipher' ;
14- import { b64ToUint8Array , uint8ArrayToB64 } from '../../../encoding/base64' ;
1514
1615const HKDF_INFO = {
1716 x25519 : util . encodeUTF8 ( 'OpenPGP X25519' ) ,
@@ -25,27 +24,12 @@ const HKDF_INFO = {
2524 */
2625export async function generate ( algo ) {
2726 switch ( algo ) {
28- case enums . publicKey . x25519 :
29- try {
30- const webCrypto = util . getWebCrypto ( ) ;
31- const webCryptoKey = await webCrypto . generateKey ( 'X25519' , true , [ 'deriveKey' , 'deriveBits' ] ) ;
32-
33- const privateKey = await webCrypto . exportKey ( 'jwk' , webCryptoKey . privateKey ) ;
34- const publicKey = await webCrypto . exportKey ( 'jwk' , webCryptoKey . publicKey ) ;
35-
36- return {
37- A : new Uint8Array ( b64ToUint8Array ( publicKey . x ) ) ,
38- k : b64ToUint8Array ( privateKey . d , true )
39- } ;
40- } catch ( err ) {
41- if ( err . name !== 'NotSupportedError' ) {
42- throw err ;
43- }
44- // k stays in little-endian, unlike legacy ECDH over curve25519
45- const k = getRandomBytes ( 32 ) ;
46- const { publicKey : A } = x25519 . box . keyPair . fromSecretKey ( k ) ;
47- return { A, k } ;
48- }
27+ case enums . publicKey . x25519 : {
28+ // k stays in little-endian, unlike legacy ECDH over curve25519
29+ const k = getRandomBytes ( 32 ) ;
30+ const { publicKey : A } = x25519 . box . keyPair . fromSecretKey ( k ) ;
31+ return { A, k } ;
32+ }
4933
5034 case enums . publicKey . x448 : {
5135 const x448 = await util . getNobleCurve ( enums . publicKey . x448 ) ;
@@ -187,32 +171,13 @@ export function getPayloadSize(algo) {
187171 */
188172export async function generateEphemeralEncryptionMaterial ( algo , recipientA ) {
189173 switch ( algo ) {
190- case enums . publicKey . x25519 :
191- try {
192- const webCrypto = util . getWebCrypto ( ) ;
193- const jwk = publicKeyToJWK ( algo , recipientA ) ;
194- const ephemeralKeyPair = await webCrypto . generateKey ( 'X25519' , true , [ 'deriveKey' , 'deriveBits' ] ) ;
195- const recipientPublicKey = await webCrypto . importKey ( 'jwk' , jwk , 'X25519' , false , [ ] ) ;
196- const sharedSecretBuffer = await webCrypto . deriveBits (
197- { name : 'X25519' , public : recipientPublicKey } ,
198- ephemeralKeyPair . privateKey ,
199- getPayloadSize ( algo ) * 8 // in bits
200- ) ;
201- const ephemeralPublicKeyJwt = await webCrypto . exportKey ( 'jwk' , ephemeralKeyPair . publicKey ) ;
202- return {
203- sharedSecret : new Uint8Array ( sharedSecretBuffer ) ,
204- ephemeralPublicKey : new Uint8Array ( b64ToUint8Array ( ephemeralPublicKeyJwt . x ) )
205- } ;
206- } catch ( err ) {
207- if ( err . name !== 'NotSupportedError' ) {
208- throw err ;
209- }
210- const ephemeralSecretKey = getRandomBytes ( getPayloadSize ( algo ) ) ;
211- const sharedSecret = x25519 . scalarMult ( ephemeralSecretKey , recipientA ) ;
212- const { publicKey : ephemeralPublicKey } = x25519 . box . keyPair . fromSecretKey ( ephemeralSecretKey ) ;
174+ case enums . publicKey . x25519 : {
175+ const ephemeralSecretKey = getRandomBytes ( getPayloadSize ( algo ) ) ;
176+ const sharedSecret = x25519 . scalarMult ( ephemeralSecretKey , recipientA ) ;
177+ const { publicKey : ephemeralPublicKey } = x25519 . box . keyPair . fromSecretKey ( ephemeralSecretKey ) ;
213178
214- return { ephemeralPublicKey, sharedSecret } ;
215- }
179+ return { ephemeralPublicKey, sharedSecret } ;
180+ }
216181 case enums . publicKey . x448 : {
217182 const x448 = await util . getNobleCurve ( enums . publicKey . x448 ) ;
218183 const ephemeralSecretKey = x448 . utils . randomPrivateKey ( ) ;
@@ -228,24 +193,7 @@ export async function generateEphemeralEncryptionMaterial(algo, recipientA) {
228193export async function recomputeSharedSecret ( algo , ephemeralPublicKey , A , k ) {
229194 switch ( algo ) {
230195 case enums . publicKey . x25519 :
231- try {
232- const webCrypto = util . getWebCrypto ( ) ;
233- const privateKeyJWK = privateKeyToJWK ( algo , A , k ) ;
234- const ephemeralPublicKeyJWK = publicKeyToJWK ( algo , ephemeralPublicKey ) ;
235- const privateKey = await webCrypto . importKey ( 'jwk' , privateKeyJWK , 'X25519' , false , [ 'deriveKey' , 'deriveBits' ] ) ;
236- const ephemeralPublicKeyReference = await webCrypto . importKey ( 'jwk' , ephemeralPublicKeyJWK , 'X25519' , false , [ ] ) ;
237- const sharedSecretBuffer = await webCrypto . deriveBits (
238- { name : 'X25519' , public : ephemeralPublicKeyReference } ,
239- privateKey ,
240- getPayloadSize ( algo ) * 8 // in bits
241- ) ;
242- return new Uint8Array ( sharedSecretBuffer ) ;
243- } catch ( err ) {
244- if ( err . name !== 'NotSupportedError' ) {
245- throw err ;
246- }
247- return x25519 . scalarMult ( k , ephemeralPublicKey ) ;
248- }
196+ return x25519 . scalarMult ( k , ephemeralPublicKey ) ;
249197 case enums . publicKey . x448 : {
250198 const x448 = await util . getNobleCurve ( enums . publicKey . x448 ) ;
251199 const sharedSecret = x448 . getSharedSecret ( k , ephemeralPublicKey ) ;
@@ -255,32 +203,3 @@ export async function recomputeSharedSecret(algo, ephemeralPublicKey, A, k) {
255203 throw new Error ( 'Unsupported ECDH algorithm' ) ;
256204 }
257205}
258-
259-
260- function publicKeyToJWK ( algo , publicKey ) {
261- switch ( algo ) {
262- case enums . publicKey . x25519 : {
263- const jwk = {
264- kty : 'OKP' ,
265- crv : 'X25519' ,
266- x : uint8ArrayToB64 ( publicKey , true ) ,
267- ext : true
268- } ;
269- return jwk ;
270- }
271- default :
272- throw new Error ( 'Unsupported ECDH algorithm' ) ;
273- }
274- }
275-
276- function privateKeyToJWK ( algo , publicKey , privateKey ) {
277- switch ( algo ) {
278- case enums . publicKey . x25519 : {
279- const jwk = publicKeyToJWK ( algo , publicKey ) ;
280- jwk . d = uint8ArrayToB64 ( privateKey , true ) ;
281- return jwk ;
282- }
283- default :
284- throw new Error ( 'Unsupported ECDH algorithm' ) ;
285- }
286- }
0 commit comments