@@ -5,9 +5,15 @@ import {
55 encodeUTF8 ,
66} from 'tweetnacl-util'
77
8- import { decryptContent , encryptMessage , generateKeypair } from './util/crypto'
8+ import {
9+ decryptContent ,
10+ encryptMessage ,
11+ generateKeypair ,
12+ verifySignedMessage ,
13+ } from './util/crypto'
914import { determineIsFormFieldsV3 } from './util/validate'
1015import CryptoBase from './crypto-base'
16+ import { MissingPublicKeyError } from './errors'
1117import {
1218 DecryptedContentV3 ,
1319 DecryptParams ,
@@ -17,8 +23,11 @@ import {
1723} from './types'
1824
1925export default class CryptoV3 extends CryptoBase {
20- constructor ( ) {
26+ signingPublicKey ?: string
27+
28+ constructor ( { signingPublicKey } : { signingPublicKey ?: string } = { } ) {
2129 super ( )
30+ this . signingPublicKey = signingPublicKey
2231 }
2332
2433 /**
@@ -62,7 +71,7 @@ export default class CryptoV3 extends CryptoBase {
6271 decryptParams : DecryptParams
6372 ) : DecryptedContentV3 | null => {
6473 try {
65- const { encryptedContent } = decryptParams
74+ const { encryptedContent, verifiedContent } = decryptParams
6675
6776 // Do not return the transformed object in `_decrypt` function as a signed
6877 // object is not encoded in UTF8 and is encoded in Base-64 instead.
@@ -85,8 +94,47 @@ export default class CryptoV3 extends CryptoBase {
8594 responses : decryptedObject as FormFieldsV3 ,
8695 }
8796
97+ /**
98+ * Note on verifiedContent decryption for cryptoV3:
99+ * Although decryption is supported, verifiedContent encryption is not supported
100+ * in cryptoV3 encrypt.
101+ * This is to keep the encryption of verifiedContent and encryptedContent similar to storage mode - where
102+ * verifiedContent and encryptedContent are defined and encrypted separately.
103+ */
104+ // decrypt verifiedContent if it exists
105+ if ( verifiedContent ) {
106+ if ( ! this . signingPublicKey ) {
107+ throw new MissingPublicKeyError (
108+ 'Public signing key must be provided when instantiating the Crypto class in order to verify verified content'
109+ )
110+ }
111+
112+ const decryptedVerifiedContent = decryptContent (
113+ submissionSecretKey ,
114+ verifiedContent
115+ )
116+
117+ if ( ! decryptedVerifiedContent ) {
118+ // Returns null if decrypting verified content failed.
119+ throw new Error ( 'Failed to decrypt verified content' )
120+ }
121+
122+ const decryptedVerifiedObject = verifySignedMessage (
123+ decryptedVerifiedContent ,
124+ this . signingPublicKey
125+ )
126+
127+ returnedObject . verified = decryptedVerifiedObject
128+ }
129+
88130 return returnedObject
89131 } catch ( err ) {
132+ // Should only throw if MissingPublicKeyError.
133+ // This library should be able to be used to encrypt and decrypt content
134+ // if the content does not contain verified fields.
135+ if ( err instanceof MissingPublicKeyError ) {
136+ throw err
137+ }
90138 return null
91139 }
92140 }
@@ -99,24 +147,34 @@ export default class CryptoV3 extends CryptoBase {
99147 * @param decryptParams.encryptedSubmissionSecretKey The encrypted submission secret key encoded with base-64.
100148 * @param decryptParams.version The version of the payload. Used to determine the decryption process to decrypt the content with.
101149 * @returns The decrypted content if successful. Else, null will be returned.
150+ * @throws {MissingPublicKeyError } if a public key is not provided when instantiating this class and is needed for verifying signed content.
102151 */
103152 decrypt = (
104153 formSecretKey : string ,
105154 decryptParams : DecryptParamsV3
106155 ) : DecryptedContentV3 | null => {
107- const { encryptedSubmissionSecretKey, ...rest } = decryptParams
156+ try {
157+ const { encryptedSubmissionSecretKey, ...rest } = decryptParams
108158
109- const submissionSecretKey = decryptContent (
110- formSecretKey ,
111- encryptedSubmissionSecretKey
112- )
159+ const submissionSecretKey = decryptContent (
160+ formSecretKey ,
161+ encryptedSubmissionSecretKey
162+ )
113163
114- if ( submissionSecretKey === null ) return null
164+ if ( submissionSecretKey === null ) return null
115165
116- return this . decryptFromSubmissionKey (
117- encodeBase64 ( submissionSecretKey ) ,
118- rest
119- )
166+ return this . decryptFromSubmissionKey (
167+ encodeBase64 ( submissionSecretKey ) ,
168+ rest
169+ )
170+
171+ } catch ( err ) {
172+ if ( err instanceof MissingPublicKeyError ) {
173+ // rethrow to let the caller decide how to handle missing signing key
174+ throw err
175+ }
176+ return null
177+ }
120178 }
121179
122180 /**
0 commit comments