@@ -33,21 +33,23 @@ import KDFParams from '../type/kdf_params';
3333import enums from '../enums' ;
3434import util from '../util' ;
3535import OID from '../type/oid' ;
36- import { Curve } from './public_key/elliptic/curves ' ;
36+ import { CurveWithOID } from './public_key/elliptic/oid_curves ' ;
3737import { UnsupportedError } from '../packet/packet' ;
38+ import ECDHXSymmetricKey from '../type/ecdh_x_symkey' ;
3839
3940/**
4041 * Encrypts data using specified algorithm and public key parameters.
4142 * See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1} for public key algorithms.
42- * @param {module:enums.publicKey } algo - Public key algorithm
43+ * @param {module:enums.publicKey } keyAlgo - Public key algorithm
44+ * @param {module:enums.symmetric } symmetricAlgo - Cipher algorithm
4345 * @param {Object } publicParams - Algorithm-specific public key parameters
44- * @param {Uint8Array } data - Data to be encrypted
46+ * @param {Uint8Array } data - Session key data to be encrypted
4547 * @param {Uint8Array } fingerprint - Recipient fingerprint
4648 * @returns {Promise<Object> } Encrypted session key parameters.
4749 * @async
4850 */
49- export async function publicKeyEncrypt ( algo , publicParams , data , fingerprint ) {
50- switch ( algo ) {
51+ export async function publicKeyEncrypt ( keyAlgo , symmetricAlgo , publicParams , data , fingerprint ) {
52+ switch ( keyAlgo ) {
5153 case enums . publicKey . rsaEncrypt :
5254 case enums . publicKey . rsaEncryptSign : {
5355 const { n, e } = publicParams ;
@@ -64,6 +66,17 @@ export async function publicKeyEncrypt(algo, publicParams, data, fingerprint) {
6466 oid , kdfParams , data , Q , fingerprint ) ;
6567 return { V, C : new ECDHSymkey ( C ) } ;
6668 }
69+ case enums . publicKey . x25519 : {
70+ if ( ! util . isAES ( symmetricAlgo ) ) {
71+ // see https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/276
72+ throw new Error ( 'X25519 keys can only encrypt AES session keys' ) ;
73+ }
74+ const { A } = publicParams ;
75+ const { ephemeralPublicKey, wrappedKey } = await publicKey . elliptic . ecdhX . encrypt (
76+ keyAlgo , data , A ) ;
77+ const C = ECDHXSymmetricKey . fromObject ( { algorithm : symmetricAlgo , wrappedKey } ) ;
78+ return { ephemeralPublicKey, C } ;
79+ }
6780 default :
6881 return [ ] ;
6982 }
@@ -105,6 +118,16 @@ export async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams,
105118 return publicKey . elliptic . ecdh . decrypt (
106119 oid , kdfParams , V , C . data , Q , d , fingerprint ) ;
107120 }
121+ case enums . publicKey . x25519 : {
122+ const { A } = publicKeyParams ;
123+ const { k } = privateKeyParams ;
124+ const { ephemeralPublicKey, C } = sessionKeyParams ;
125+ if ( ! util . isAES ( C . algorithm ) ) {
126+ throw new Error ( 'AES session key expected' ) ;
127+ }
128+ return publicKey . elliptic . ecdhX . decrypt (
129+ algo , ephemeralPublicKey , C . wrappedKey , A , k ) ;
130+ }
108131 default :
109132 throw new Error ( 'Unknown public key encryption algorithm.' ) ;
110133 }
@@ -145,7 +168,8 @@ export function parsePublicKeyParams(algo, bytes) {
145168 const Q = util . readMPI ( bytes . subarray ( read ) ) ; read += Q . length + 2 ;
146169 return { read : read , publicParams : { oid, Q } } ;
147170 }
148- case enums . publicKey . eddsa : {
171+ case enums . publicKey . eddsa :
172+ case enums . publicKey . ed25519Legacy : {
149173 const oid = new OID ( ) ; read += oid . read ( bytes ) ;
150174 checkSupportedCurve ( oid ) ;
151175 let Q = util . readMPI ( bytes . subarray ( read ) ) ; read += Q . length + 2 ;
@@ -159,6 +183,11 @@ export function parsePublicKeyParams(algo, bytes) {
159183 const kdfParams = new KDFParams ( ) ; read += kdfParams . read ( bytes . subarray ( read ) ) ;
160184 return { read : read , publicParams : { oid, Q, kdfParams } } ;
161185 }
186+ case enums . publicKey . ed25519 :
187+ case enums . publicKey . x25519 : {
188+ const A = bytes . subarray ( read , read + 32 ) ; read += A . length ;
189+ return { read, publicParams : { A } } ;
190+ }
162191 default :
163192 throw new UnsupportedError ( 'Unknown public key encryption algorithm.' ) ;
164193 }
@@ -190,17 +219,26 @@ export function parsePrivateKeyParams(algo, bytes, publicParams) {
190219 }
191220 case enums . publicKey . ecdsa :
192221 case enums . publicKey . ecdh : {
193- const curve = new Curve ( publicParams . oid ) ;
222+ const curve = new CurveWithOID ( publicParams . oid ) ;
194223 let d = util . readMPI ( bytes . subarray ( read ) ) ; read += d . length + 2 ;
195224 d = util . leftPad ( d , curve . payloadSize ) ;
196225 return { read, privateParams : { d } } ;
197226 }
198- case enums . publicKey . eddsa : {
199- const curve = new Curve ( publicParams . oid ) ;
227+ case enums . publicKey . eddsa :
228+ case enums . publicKey . ed25519Legacy : {
229+ const curve = new CurveWithOID ( publicParams . oid ) ;
200230 let seed = util . readMPI ( bytes . subarray ( read ) ) ; read += seed . length + 2 ;
201231 seed = util . leftPad ( seed , curve . payloadSize ) ;
202232 return { read, privateParams : { seed } } ;
203233 }
234+ case enums . publicKey . ed25519 : {
235+ const seed = bytes . subarray ( read , read + 32 ) ; read += seed . length ;
236+ return { read, privateParams : { seed } } ;
237+ }
238+ case enums . publicKey . x25519 : {
239+ const k = bytes . subarray ( read , read + 32 ) ; read += k . length ;
240+ return { read, privateParams : { k } } ;
241+ }
204242 default :
205243 throw new UnsupportedError ( 'Unknown public key encryption algorithm.' ) ;
206244 }
@@ -238,6 +276,16 @@ export function parseEncSessionKeyParams(algo, bytes) {
238276 const C = new ECDHSymkey ( ) ; C . read ( bytes . subarray ( read ) ) ;
239277 return { V, C } ;
240278 }
279+ // Algorithm-Specific Fields for X25519 encrypted session keys:
280+ // - 32 octets representing an ephemeral X25519 public key.
281+ // - A one-octet size of the following fields.
282+ // - The one-octet algorithm identifier, if it was passed (in the case of a v3 PKESK packet).
283+ // - The encrypted session key.
284+ case enums . publicKey . x25519 : {
285+ const ephemeralPublicKey = bytes . subarray ( read , read + 32 ) ; read += ephemeralPublicKey . length ;
286+ const C = new ECDHXSymmetricKey ( ) ; C . read ( bytes . subarray ( read ) ) ;
287+ return { ephemeralPublicKey, C } ;
288+ }
241289 default :
242290 throw new UnsupportedError ( 'Unknown public key encryption algorithm.' ) ;
243291 }
@@ -250,9 +298,12 @@ export function parseEncSessionKeyParams(algo, bytes) {
250298 * @returns {Uint8Array } The array containing the MPIs.
251299 */
252300export function serializeParams ( algo , params ) {
301+ // Some algorithms do not rely on MPIs to store the binary params
302+ const algosWithNativeRepresentation = new Set ( [ enums . publicKey . ed25519 , enums . publicKey . x25519 ] ) ;
253303 const orderedParams = Object . keys ( params ) . map ( name => {
254304 const param = params [ name ] ;
255- return util . isUint8Array ( param ) ? util . uint8ArrayToMPI ( param ) : param . write ( ) ;
305+ if ( ! util . isUint8Array ( param ) ) return param . write ( ) ;
306+ return algosWithNativeRepresentation . has ( algo ) ? param : util . uint8ArrayToMPI ( param ) ;
256307 } ) ;
257308 return util . concatUint8Array ( orderedParams ) ;
258309}
@@ -281,6 +332,7 @@ export function generateParams(algo, bits, oid) {
281332 publicParams : { oid : new OID ( oid ) , Q }
282333 } ) ) ;
283334 case enums . publicKey . eddsa :
335+ case enums . publicKey . ed25519Legacy :
284336 return publicKey . elliptic . generate ( oid ) . then ( ( { oid, Q, secret } ) => ( {
285337 privateParams : { seed : secret } ,
286338 publicParams : { oid : new OID ( oid ) , Q }
@@ -294,6 +346,16 @@ export function generateParams(algo, bits, oid) {
294346 kdfParams : new KDFParams ( { hash, cipher } )
295347 }
296348 } ) ) ;
349+ case enums . publicKey . ed25519 :
350+ return publicKey . elliptic . eddsa . generate ( algo ) . then ( ( { A, seed } ) => ( {
351+ privateParams : { seed } ,
352+ publicParams : { A }
353+ } ) ) ;
354+ case enums . publicKey . x25519 :
355+ return publicKey . elliptic . ecdhX . generate ( algo ) . then ( ( { A, k } ) => ( {
356+ privateParams : { k } ,
357+ publicParams : { A }
358+ } ) ) ;
297359 case enums . publicKey . dsa :
298360 case enums . publicKey . elgamal :
299361 throw new Error ( 'Unsupported algorithm for key generation.' ) ;
@@ -339,10 +401,21 @@ export async function validateParams(algo, publicParams, privateParams) {
339401 const { d } = privateParams ;
340402 return algoModule . validateParams ( oid , Q , d ) ;
341403 }
342- case enums . publicKey . eddsa : {
343- const { oid, Q } = publicParams ;
404+ case enums . publicKey . eddsa :
405+ case enums . publicKey . ed25519Legacy : {
406+ const { Q, oid } = publicParams ;
407+ const { seed } = privateParams ;
408+ return publicKey . elliptic . eddsaLegacy . validateParams ( oid , Q , seed ) ;
409+ }
410+ case enums . publicKey . ed25519 : {
411+ const { A } = publicParams ;
344412 const { seed } = privateParams ;
345- return publicKey . elliptic . eddsa . validateParams ( oid , Q , seed ) ;
413+ return publicKey . elliptic . eddsa . validateParams ( algo , A , seed ) ;
414+ }
415+ case enums . publicKey . x25519 : {
416+ const { A } = publicParams ;
417+ const { k } = privateParams ;
418+ return publicKey . elliptic . ecdhX . validateParams ( algo , A , k ) ;
346419 }
347420 default :
348421 throw new Error ( 'Unknown public key algorithm.' ) ;
0 commit comments