1
1
/*
2
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
3
* Licensed under the MIT License.
4
+ *
4
5
*/
5
6
import { BrowserStringUtils } from "../utils/BrowserStringUtils" ;
6
7
import { BrowserAuthError } from "../error/BrowserAuthError" ;
7
-
8
+ import { StringUtils } from "@azure/msal-common" ;
9
+ /**
10
+ * See here for more info on RsaHashedKeyGenParams: https://developer.mozilla.org/en-US/docs/Web/API/RsaHashedKeyGenParams
11
+ */
12
+ // RSA KeyGen Algorithm
13
+ const PKCS1_V15_KEYGEN_ALG = "RSASSA-PKCS1-v1_5" ;
8
14
// SHA-256 hashing algorithm
9
- const HASH_ALG = "SHA-256" ;
15
+ const S256_HASH_ALG = "SHA-256" ;
16
+ // MOD length for PoP tokens
17
+ const MODULUS_LENGTH = 2048 ;
18
+ // Public Exponent
19
+ const PUBLIC_EXPONENT : Uint8Array = new Uint8Array ( [ 0x01 , 0x00 , 0x01 ] ) ;
20
+ // JWK Key Format string
21
+ const KEY_FORMAT_JWK = "jwk" ;
10
22
11
23
/**
12
24
* This class implements functions used by the browser library to perform cryptography operations such as
13
25
* hashing and encoding. It also has helper functions to validate the availability of specific APIs.
14
26
*/
15
27
export class BrowserCrypto {
16
28
29
+ private _keygenAlgorithmOptions : RsaHashedKeyGenParams ;
30
+
17
31
constructor ( ) {
18
32
if ( ! ( this . hasCryptoAPI ( ) ) ) {
19
33
throw BrowserAuthError . createCryptoNotAvailableError ( "Browser crypto or msCrypto object not available." ) ;
20
34
}
35
+
36
+ this . _keygenAlgorithmOptions = {
37
+ name : PKCS1_V15_KEYGEN_ALG ,
38
+ hash : S256_HASH_ALG ,
39
+ modulusLength : MODULUS_LENGTH ,
40
+ publicExponent : PUBLIC_EXPONENT
41
+ } ;
21
42
}
22
43
23
44
/**
@@ -27,7 +48,7 @@ export class BrowserCrypto {
27
48
async sha256Digest ( dataString : string ) : Promise < ArrayBuffer > {
28
49
const data = BrowserStringUtils . stringToUtf8Arr ( dataString ) ;
29
50
30
- return this . hasIECrypto ( ) ? this . getMSCryptoDigest ( HASH_ALG , data ) : this . getSubtleCryptoDigest ( HASH_ALG , data ) ;
51
+ return this . hasIECrypto ( ) ? this . getMSCryptoDigest ( S256_HASH_ALG , data ) : this . getSubtleCryptoDigest ( S256_HASH_ALG , data ) ;
31
52
}
32
53
33
54
/**
@@ -43,17 +64,25 @@ export class BrowserCrypto {
43
64
}
44
65
45
66
/**
46
- * Checks whether IE crypto (AKA msCrypto) is available.
67
+ * Generates a keypair based on current keygen algorithm config.
68
+ * @param extractable
69
+ * @param usages
47
70
*/
48
- private hasIECrypto ( ) : boolean {
49
- return ! ! window [ "msCrypto" ] ;
71
+ async generateKeyPair ( extractable : boolean , usages : Array < KeyUsage > ) : Promise < CryptoKeyPair > {
72
+ return (
73
+ this . hasIECrypto ( ) ?
74
+ this . msCryptoGenerateKey ( extractable , usages )
75
+ : window . crypto . subtle . generateKey ( this . _keygenAlgorithmOptions , extractable , usages )
76
+ ) as Promise < CryptoKeyPair > ;
50
77
}
51
78
52
79
/**
53
- * Check whether browser crypto is available.
80
+ * Export key as given KeyFormat (see above)
81
+ * @param key
82
+ * @param format
54
83
*/
55
- private hasBrowserCrypto ( ) : boolean {
56
- return ! ! window . crypto ;
84
+ async exportJwk ( key : CryptoKey ) : Promise < JsonWebKey > {
85
+ return this . hasIECrypto ( ) ? this . msCryptoExportJwk ( key ) : window . crypto . subtle . exportKey ( KEY_FORMAT_JWK , key ) ;
57
86
}
58
87
59
88
/**
@@ -63,17 +92,32 @@ export class BrowserCrypto {
63
92
return this . hasIECrypto ( ) || this . hasBrowserCrypto ( ) ;
64
93
}
65
94
95
+ /**
96
+ * Checks whether IE crypto (AKA msCrypto) is available.
97
+ */
98
+ private hasIECrypto ( ) : boolean {
99
+ return "msCrypto" in window ;
100
+ }
101
+
102
+ /**
103
+ * Check whether browser crypto is available.
104
+ */
105
+ private hasBrowserCrypto ( ) : boolean {
106
+ return "crypto" in window ;
107
+ }
108
+
66
109
/**
67
110
* Helper function for SHA digest.
68
111
* @param algorithm
69
112
* @param data
70
113
*/
71
114
private async getSubtleCryptoDigest ( algorithm : string , data : Uint8Array ) : Promise < ArrayBuffer > {
115
+ console . log ( algorithm ) ;
72
116
return window . crypto . subtle . digest ( algorithm , data ) ;
73
117
}
74
118
75
119
/**
76
- * Helper function for SHA digest.
120
+ * IE Helper function for SHA digest.
77
121
* @param algorithm
78
122
* @param data
79
123
*/
@@ -88,4 +132,56 @@ export class BrowserCrypto {
88
132
} ) ;
89
133
} ) ;
90
134
}
135
+
136
+ private async msCryptoGenerateKey ( extractable : boolean , usages : Array < KeyUsage > ) : Promise < CryptoKeyPair > {
137
+ return new Promise ( ( resolve : any , reject : any ) => {
138
+ const msGenerateKey = window [ "msCrypto" ] . subtle . generateKey ( this . _keygenAlgorithmOptions , extractable , usages ) ;
139
+ msGenerateKey . addEventListener ( "complete" , ( e : { target : { result : CryptoKeyPair | PromiseLike < CryptoKeyPair > ; } ; } ) => {
140
+ resolve ( e . target . result ) ;
141
+ } ) ;
142
+
143
+ msGenerateKey . addEventListener ( "error" , ( error : any ) => {
144
+ reject ( error ) ;
145
+ } ) ;
146
+ } ) ;
147
+ }
148
+
149
+ /**
150
+ * IE Helper function for exporting keys
151
+ * @param key
152
+ * @param format
153
+ */
154
+ private async msCryptoExportJwk ( key : CryptoKey ) : Promise < JsonWebKey > {
155
+ return new Promise ( ( resolve : any , reject : any ) => {
156
+ const msExportKey = window [ "msCrypto" ] . subtle . exportKey ( KEY_FORMAT_JWK , key ) ;
157
+ msExportKey . addEventListener ( "complete" , ( e : { target : { result : ArrayBuffer ; } ; } ) => {
158
+ const resultBuffer : ArrayBuffer = e . target . result ;
159
+
160
+ const resultString = BrowserStringUtils . utf8ArrToString ( new Uint8Array ( resultBuffer ) )
161
+ . replace ( / \r / g, "" )
162
+ . replace ( / \n / g, "" )
163
+ . replace ( / \t / g, "" )
164
+ . split ( " " ) . join ( "" )
165
+ . replace ( "\u0000" , "" ) ;
166
+
167
+ try {
168
+ resolve ( JSON . parse ( resultString ) ) ;
169
+ } catch ( e ) {
170
+ reject ( e ) ;
171
+ }
172
+ } ) ;
173
+
174
+ msExportKey . addEventListener ( "error" , ( error : any ) => {
175
+ reject ( error ) ;
176
+ } ) ;
177
+ } ) ;
178
+ }
179
+
180
+ /**
181
+ * Returns stringified jwk.
182
+ * @param jwk
183
+ */
184
+ static getJwkString ( jwk : JsonWebKey ) : string {
185
+ return JSON . stringify ( jwk , Object . keys ( jwk ) . sort ( ) ) ;
186
+ }
91
187
}
0 commit comments