Skip to content

Commit 12d1661

Browse files
authored
fix: Better timingSafeEqual definition (#203)
1 parent dd28254 commit 12d1661

File tree

1 file changed

+30
-29
lines changed

1 file changed

+30
-29
lines changed

modules/material-management/src/cryptographic_material.ts

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -68,36 +68,37 @@ export const supportsKeyObject = (function () {
6868
* it is no longer needed.
6969
*/
7070

71-
let timingSafeEqual: (a: Uint8Array, b: Uint8Array) => boolean
72-
try {
73-
/* It is possible for `require` to return an empty object, or an object
74-
* that does not implement `timingSafeEqual`.
75-
* in this case I need a fallback
76-
*/
77-
const { timingSafeEqual: nodeTimingSafeEqual } = require('crypto')
78-
timingSafeEqual = nodeTimingSafeEqual || portableTimingSafeEqual
79-
} catch (e) {
80-
timingSafeEqual = portableTimingSafeEqual
81-
}
82-
/* https://codahale.com/a-lesson-in-timing-attacks/ */
83-
function portableTimingSafeEqual (a: Uint8Array, b: Uint8Array) {
84-
/* It is *possible* that a runtime could optimize this constant time function.
85-
* Adding `eval` should prevent the optimization, but this is no grantee.
86-
* If you copy this function for your own use, make sure to educate yourself.
87-
* Side channel attacks are pernicious and subtle.
88-
*/
89-
eval('') // eslint-disable-line no-eval
90-
/* Check for early return (Postcondition) UNTESTED: Size is well-know information.
91-
* and does not leak information about contents.
92-
*/
93-
if (a.byteLength !== b.byteLength) return false
94-
95-
let diff = 0
96-
for (let i = 0; i < b.length; i++) {
97-
diff |= a[i] ^ b[i]
71+
const timingSafeEqual: (a: Uint8Array, b: Uint8Array) => boolean = (function () {
72+
try {
73+
/* It is possible for `require` to return an empty object, or an object
74+
* that does not implement `timingSafeEqual`.
75+
* in this case I need a fallback
76+
*/
77+
const { timingSafeEqual: nodeTimingSafeEqual } = require('crypto')
78+
return nodeTimingSafeEqual || portableTimingSafeEqual
79+
} catch (e) {
80+
return portableTimingSafeEqual
9881
}
99-
return (diff === 0)
100-
}
82+
/* https://codahale.com/a-lesson-in-timing-attacks/ */
83+
function portableTimingSafeEqual (a: Uint8Array, b: Uint8Array) {
84+
/* It is *possible* that a runtime could optimize this constant time function.
85+
* Adding `eval` should prevent the optimization, but this is no grantee.
86+
* If you copy this function for your own use, make sure to educate yourself.
87+
* Side channel attacks are pernicious and subtle.
88+
*/
89+
eval('') // eslint-disable-line no-eval
90+
/* Check for early return (Postcondition) UNTESTED: Size is well-know information.
91+
* and does not leak information about contents.
92+
*/
93+
if (a.byteLength !== b.byteLength) return false
94+
95+
let diff = 0
96+
for (let i = 0; i < b.length; i++) {
97+
diff |= a[i] ^ b[i]
98+
}
99+
return (diff === 0)
100+
}
101+
})()
101102

102103
export interface FunctionalCryptographicMaterial {
103104
hasValidKey: () => boolean

0 commit comments

Comments
 (0)