1
1
/*!
2
- * keygrip
2
+ * Based on https://github.com/crypto-utils/ keygrip/blob/master/index.js
3
3
* Copyright(c) 2011-2014 Jed Schmidt
4
4
* Copyright(c) 2020 Christian Norrman
5
5
* MIT Licensed
6
6
*/
7
-
8
- import { HmacSha256 , HmacSha512 } from './deps.ts' ;
9
-
10
- const SANITIZE_REGEXP = / \/ | \+ | = / g;
11
- const SANITIZE_REPLACERS = {
12
- "/" : "_" ,
13
- "+" : "-" ,
14
- "=" : "" ,
15
- } as Record < string , string > ;
7
+ import { HmacSha256 , HmacSha512 , base64url } from './deps.ts' ;
16
8
17
9
export enum Algorithm {
18
10
SHA256 = 'sha256' ,
@@ -21,10 +13,9 @@ export enum Algorithm {
21
13
22
14
export class Keygrip {
23
15
#keys: string [ ] ;
24
- #decoder: TextDecoder ;
25
16
#algo: Algorithm ;
26
17
27
- constructor ( keys : string [ ] , algo : Algorithm = Algorithm . SHA256 , enc : string = 'base64' ) {
18
+ constructor ( keys : string [ ] , algo : Algorithm = Algorithm . SHA256 ) {
28
19
if ( ! keys || ! keys . length ) {
29
20
throw new Error ( 'Keys must be provided.' ) ;
30
21
} else if ( algo != 'sha256' && algo != 'sha512' ) {
@@ -33,7 +24,6 @@ export class Keygrip {
33
24
34
25
this . #keys = keys ;
35
26
this . #algo = algo ;
36
- this . #decoder = new TextDecoder ( enc ) ;
37
27
}
38
28
39
29
sign ( data : string , key ?: string ) : string {
@@ -47,20 +37,27 @@ export class Keygrip {
47
37
const hash = new HmacSha512 ( key ) ;
48
38
buffer = hash . update ( data ) . arrayBuffer ( ) ;
49
39
} else {
50
- // Required for typescript
51
40
throw new Error ( 'Algorithm invalid' ) ;
52
41
}
53
42
54
- return this . #decoder
55
- . decode ( buffer )
56
- . replace ( SANITIZE_REGEXP , s => SANITIZE_REPLACERS [ s ] ) ;
43
+ return base64url . encode ( buffer ) ;
57
44
}
58
45
59
46
verify ( data : string , digest : string ) : boolean {
60
47
return this . index ( data , digest ) != - 1 ;
61
48
}
62
49
63
50
index ( data : string , digest : string ) : number {
64
- return this . #keys. findIndex ( key => digest === this . sign ( data , key ) ) ;
51
+ return this . #keys. findIndex ( key => this . compare ( digest , this . sign ( data , key ) ) ) ;
52
+ }
53
+
54
+ // Timing safe compare using Brad Hill's Double HMAC pattern
55
+ private compare ( a : string , b : string ) : boolean {
56
+ const key = crypto . getRandomValues ( new Uint8Array ( 32 ) ) ;
57
+ const hmac = new HmacSha256 ( key ) ;
58
+ const ah = hmac . update ( a ) . digest ( ) ;
59
+ const bh = hmac . update ( b ) . digest ( ) ;
60
+
61
+ return ah . length === bh . length && ah . every ( ( x , i ) => x === bh [ i ] ) ;
65
62
}
66
63
}
0 commit comments