-
-
Notifications
You must be signed in to change notification settings - Fork 31
feat(DEP0106): migrate from crypto.createCipher & crypto.createDecipher
#265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
crypto-createcipheriv-migration): introducenode:crypto.createCipher & node:crypto.createDecipher
|
@nodejs/crypto I'm not familiar with this part of node. could you check the |
node:crypto.createCipher & node:crypto.createDeciphercrypto.createCipher & crypto.createDecipher
JakobJingleheimer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fine to me! I'd like someone from the crypto team to take a look at the before & after test fixtures though before landing this.
| import { | ||
| getNodeImportCalls, | ||
| getNodeImportStatements, | ||
| } from '@nodejs/codemod-utils/ast-grep/import-statement'; | ||
| import { getNodeRequireCalls } from '@nodejs/codemod-utils/ast-grep/require-call'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: there's a consolidated util for this now
| if (kind === 'cipher') { | ||
| const replacement = buildCipherReplacement({ | ||
| binding, | ||
| algorithm, | ||
| password, | ||
| options: optionsText, | ||
| }); | ||
| edits.push(call.replace(replacement)); | ||
| } else { | ||
| const replacement = buildDecipherReplacement({ | ||
| binding, | ||
| algorithm, | ||
| password, | ||
| options: optionsText, | ||
| }); | ||
| edits.push(call.replace(replacement)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be DRYed up :)
| if (kind === 'cipher') { | |
| const replacement = buildCipherReplacement({ | |
| binding, | |
| algorithm, | |
| password, | |
| options: optionsText, | |
| }); | |
| edits.push(call.replace(replacement)); | |
| } else { | |
| const replacement = buildDecipherReplacement({ | |
| binding, | |
| algorithm, | |
| password, | |
| options: optionsText, | |
| }); | |
| edits.push(call.replace(replacement)); | |
| } | |
| const builder = kind === 'cipher' ? buildCipherReplacement : buildDecipherReplacement; | |
| const replacement = builder({ | |
| binding, | |
| algorithm, | |
| password, | |
| options: optionsText, | |
| }); | |
| edits.push(call.replace(replacement)); |
If buildCipherReplacement & buildDecipherReplacement can be deduplicated:
| if (kind === 'cipher') { | |
| const replacement = buildCipherReplacement({ | |
| binding, | |
| algorithm, | |
| password, | |
| options: optionsText, | |
| }); | |
| edits.push(call.replace(replacement)); | |
| } else { | |
| const replacement = buildDecipherReplacement({ | |
| binding, | |
| algorithm, | |
| password, | |
| options: optionsText, | |
| }); | |
| edits.push(call.replace(replacement)); | |
| } | |
| const replacement = buildDeCipherReplacement({ | |
| binding, | |
| algorithm, | |
| password, | |
| options: optionsText, | |
| }, kind); | |
| edits.push(call.replace(replacement)); |
| function buildCipherReplacement(params: { | ||
| binding: string; | ||
| algorithm: string; | ||
| password: string; | ||
| options?: string; | ||
| }): string { | ||
| const { binding, algorithm, password, options } = params; | ||
| const randomBytesCall = getMemberAccess(binding, 'randomBytes'); | ||
| const scryptCall = getMemberAccess(binding, 'scryptSync'); | ||
| const cipherCall = getCallableBinding(binding, 'createCipheriv'); | ||
|
|
||
| return dedent(` | ||
| (() => { | ||
| const __dep0106Salt = ${randomBytesCall}(16); | ||
| const __dep0106Key = ${scryptCall}(${password}, __dep0106Salt, 32); | ||
| const __dep0106Iv = ${randomBytesCall}(16); | ||
| // DEP0106: Persist __dep0106Salt and __dep0106Iv with the ciphertext so it can be decrypted later. | ||
| // DEP0106: Adjust the derived key length (32 bytes) and IV length to match the chosen algorithm. | ||
| return ${cipherCall}(${algorithm}, __dep0106Key, __dep0106Iv${options ? `, ${options}` : ''}); | ||
| })() | ||
| `); | ||
| } | ||
|
|
||
| function buildDecipherReplacement(params: { | ||
| binding: string; | ||
| algorithm: string; | ||
| password: string; | ||
| options?: string; | ||
| }): string { | ||
| const { binding, algorithm, password, options } = params; | ||
| const scryptCall = getMemberAccess(binding, 'scryptSync'); | ||
| const decipherCall = getCallableBinding(binding, 'createDecipheriv'); | ||
|
|
||
| return dedent(` | ||
| (() => { | ||
| // DEP0106: Replace the placeholders below with the salt and IV that were stored with the ciphertext. | ||
| const __dep0106Salt = /* TODO: stored salt Buffer */ Buffer.alloc(16); | ||
| const __dep0106Iv = /* TODO: stored IV Buffer */ Buffer.alloc(16); | ||
| const __dep0106Key = ${scryptCall}(${password}, __dep0106Salt, 32); | ||
| // DEP0106: Ensure __dep0106Salt and __dep0106Iv match the values used during encryption. | ||
| return ${decipherCall}(${algorithm}, __dep0106Key, __dep0106Iv${options ? `, ${options}` : ''}); | ||
| })() | ||
| `); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are nearly identical. I think they can be DRYed up:
| function buildCipherReplacement(params: { | |
| binding: string; | |
| algorithm: string; | |
| password: string; | |
| options?: string; | |
| }): string { | |
| const { binding, algorithm, password, options } = params; | |
| const randomBytesCall = getMemberAccess(binding, 'randomBytes'); | |
| const scryptCall = getMemberAccess(binding, 'scryptSync'); | |
| const cipherCall = getCallableBinding(binding, 'createCipheriv'); | |
| return dedent(` | |
| (() => { | |
| const __dep0106Salt = ${randomBytesCall}(16); | |
| const __dep0106Key = ${scryptCall}(${password}, __dep0106Salt, 32); | |
| const __dep0106Iv = ${randomBytesCall}(16); | |
| // DEP0106: Persist __dep0106Salt and __dep0106Iv with the ciphertext so it can be decrypted later. | |
| // DEP0106: Adjust the derived key length (32 bytes) and IV length to match the chosen algorithm. | |
| return ${cipherCall}(${algorithm}, __dep0106Key, __dep0106Iv${options ? `, ${options}` : ''}); | |
| })() | |
| `); | |
| } | |
| function buildDecipherReplacement(params: { | |
| binding: string; | |
| algorithm: string; | |
| password: string; | |
| options?: string; | |
| }): string { | |
| const { binding, algorithm, password, options } = params; | |
| const scryptCall = getMemberAccess(binding, 'scryptSync'); | |
| const decipherCall = getCallableBinding(binding, 'createDecipheriv'); | |
| return dedent(` | |
| (() => { | |
| // DEP0106: Replace the placeholders below with the salt and IV that were stored with the ciphertext. | |
| const __dep0106Salt = /* TODO: stored salt Buffer */ Buffer.alloc(16); | |
| const __dep0106Iv = /* TODO: stored IV Buffer */ Buffer.alloc(16); | |
| const __dep0106Key = ${scryptCall}(${password}, __dep0106Salt, 32); | |
| // DEP0106: Ensure __dep0106Salt and __dep0106Iv match the values used during encryption. | |
| return ${decipherCall}(${algorithm}, __dep0106Key, __dep0106Iv${options ? `, ${options}` : ''}); | |
| })() | |
| `); | |
| } | |
| function buildDeCipherReplacement( | |
| { | |
| binding, | |
| algorithm, | |
| password, | |
| options, | |
| }: { | |
| binding: string; | |
| algorithm: string; | |
| password: string; | |
| options?: string; | |
| }, | |
| kind: 'decipher' | 'cipher' | |
| ): string { | |
| const scryptCall = getMemberAccess(binding, 'scryptSync'); | |
| const method = getCallableBinding(binding, kind === 'cipher' ? 'createCipheriv' : 'createDecipheriv'); | |
| return dedent(` | |
| (() => { | |
| const __dep0106Salt = ${randomBytesCall}(16); | |
| const __dep0106Key = ${scryptCall}(${password}, __dep0106Salt, 32); | |
| const __dep0106Iv = ${randomBytesCall}(16); | |
| // DEP0106: Persist __dep0106Salt and __dep0106Iv with the ciphertext so it can be decrypted later. | |
| // DEP0106: Adjust the derived key length (32 bytes) and IV length to match the chosen algorithm. | |
| return ${method}(${algorithm}, __dep0106Key, __dep0106Iv${options ? `, ${options}` : ''}); | |
| })() | |
| `); | |
| } |
Description
@nodejs/v20-to-v22Related issue
close #264