1
1
import { createActor , app_backend } from "../../declarations/app_backend" ;
2
- import * as vetkd from "ic-vetkd-utils " ;
2
+ import { TransportSecretKey , EncryptedVetKey , DerivedPublicKey , IbeCiphertext , IbeIdentity , IbeSeed } from "@dfinity/vetkeys " ;
3
3
import { AuthClient } from "@dfinity/auth-client"
4
4
import { HttpAgent , Actor } from "@dfinity/agent" ;
5
5
import { Principal } from "@dfinity/principal" ;
6
6
7
- let fetched_symmetric_key = null ;
7
+ let fetched_derived_key_material = null ;
8
8
let app_backend_actor = app_backend ;
9
9
let app_backend_principal = await Actor . agentOf ( app_backend_actor ) . getPrincipal ( ) ;
10
10
document . getElementById ( "principal" ) . innerHTML = annotated_principal ( app_backend_principal ) ;
11
11
12
- document . getElementById ( "get_symmetric_key_form " ) . addEventListener ( "submit" , async ( e ) => {
12
+ document . getElementById ( "get_vetkey_form " ) . addEventListener ( "submit" , async ( e ) => {
13
13
e . preventDefault ( ) ;
14
14
const button = e . target . querySelector ( "button" ) ;
15
15
button . setAttribute ( "disabled" , true ) ;
16
- const result = document . getElementById ( "get_symmetric_key_result " ) ;
16
+ const result = document . getElementById ( "get_vetkey_result " ) ;
17
17
18
- result . innerText = "Fetching symmetric key ..." ;
19
- const aes_256_key = await get_aes_256_gcm_key ( ) ;
20
- result . innerText = "Done. AES-GCM-256 key available for local usage." ;
18
+ result . innerText = "Fetching vetKey ..." ;
19
+ const derived_key_material = await get_derived_key_material ( ) ;
20
+ result . innerText = "Done. vetKey available for local usage." ;
21
21
22
22
button . removeAttribute ( "disabled" ) ;
23
23
24
- fetched_symmetric_key = aes_256_key ;
24
+ fetched_derived_key_material = derived_key_material ;
25
25
update_plaintext_button_state ( ) ;
26
26
update_ciphertext_button_state ( ) ;
27
27
@@ -35,9 +35,11 @@ document.getElementById("encrypt_form").addEventListener("submit", async (e) =>
35
35
const result = document . getElementById ( "encrypt_result" ) ;
36
36
37
37
result . innerText = "Encrypting..." ;
38
- const ciphertext = await aes_gcm_encrypt ( document . getElementById ( "plaintext" ) . value , fetched_symmetric_key ) ;
38
+ const message = document . getElementById ( "plaintext" ) . value ;
39
+ const message_encoded = new TextEncoder ( ) . encode ( message ) ;
40
+ const ciphertext_hex = hex_encode ( await fetched_derived_key_material . encryptMessage ( message_encoded , "vetkd-demo" ) ) ;
39
41
40
- result . innerText = "ciphertext: " + ciphertext ;
42
+ result . innerText = "ciphertext: " + ciphertext_hex ;
41
43
42
44
button . removeAttribute ( "disabled" ) ;
43
45
return false ;
@@ -51,8 +53,10 @@ document.getElementById("decrypt_form").addEventListener("submit", async (e) =>
51
53
52
54
result . innerText = "Decrypting..." ;
53
55
try {
54
- const plaintext = await aes_gcm_decrypt ( document . getElementById ( "ciphertext" ) . value , fetched_symmetric_key ) ;
55
- result . innerText = "plaintext: " + plaintext ;
56
+ const ciphertext_hex = document . getElementById ( "ciphertext" ) . value ;
57
+ const plaintext_bytes = await fetched_derived_key_material . decryptMessage ( hex_decode ( ciphertext_hex ) , "vetkd-demo" ) ;
58
+ const plaintext_string = new TextDecoder ( ) . decode ( plaintext_bytes ) ;
59
+ result . innerText = "plaintext: " + plaintext_string ;
56
60
} catch ( e ) {
57
61
result . innerText = "Error: " + e ;
58
62
}
@@ -71,7 +75,7 @@ document.getElementById("ciphertext").addEventListener("keyup", async (e) => {
71
75
72
76
function update_plaintext_button_state ( ) {
73
77
const submit_plaintext_button = document . getElementById ( "submit_plaintext" ) ;
74
- if ( document . getElementById ( "plaintext" ) . value === "" || fetched_symmetric_key === null ) {
78
+ if ( document . getElementById ( "plaintext" ) . value === "" || fetched_derived_key_material === null ) {
75
79
submit_plaintext_button . setAttribute ( "disabled" , true ) ;
76
80
} else {
77
81
submit_plaintext_button . removeAttribute ( "disabled" ) ;
@@ -80,54 +84,25 @@ function update_plaintext_button_state() {
80
84
81
85
function update_ciphertext_button_state ( ) {
82
86
const submit_ciphertext_button = document . getElementById ( "submit_ciphertext" ) ;
83
- if ( document . getElementById ( "ciphertext" ) . value === "" || fetched_symmetric_key === null ) {
87
+ if ( document . getElementById ( "ciphertext" ) . value === "" || fetched_derived_key_material === null ) {
84
88
submit_ciphertext_button . setAttribute ( "disabled" , true ) ;
85
89
} else {
86
90
submit_ciphertext_button . removeAttribute ( "disabled" ) ;
87
91
}
88
92
}
89
93
90
- async function get_aes_256_gcm_key ( ) {
91
- const seed = window . crypto . getRandomValues ( new Uint8Array ( 32 ) ) ;
92
- const tsk = new vetkd . TransportSecretKey ( seed ) ;
93
- const ek_bytes_hex = await app_backend_actor . encrypted_symmetric_key_for_caller ( tsk . public_key ( ) ) ;
94
+ async function get_derived_key_material ( ) {
95
+ const tsk = TransportSecretKey . random ( ) ;
96
+
97
+ const ek_bytes_hex = await app_backend_actor . encrypted_symmetric_key_for_caller ( tsk . publicKeyBytes ( ) ) ;
98
+ const encryptedVetKey = new EncryptedVetKey ( hex_decode ( ek_bytes_hex ) ) ;
99
+
94
100
const pk_bytes_hex = await app_backend_actor . symmetric_key_verification_key ( ) ;
95
- return tsk . decrypt_and_hash (
96
- hex_decode ( ek_bytes_hex ) ,
97
- hex_decode ( pk_bytes_hex ) ,
98
- app_backend_principal . toUint8Array ( ) ,
99
- 32 ,
100
- new TextEncoder ( ) . encode ( "aes-256-gcm" )
101
- ) ;
102
- }
101
+ const dpk = DerivedPublicKey . deserialize ( hex_decode ( pk_bytes_hex ) ) ;
103
102
104
- async function aes_gcm_encrypt ( message , rawKey ) {
105
- const iv = window . crypto . getRandomValues ( new Uint8Array ( 12 ) ) ; // 96-bits; unique per message
106
- const aes_key = await window . crypto . subtle . importKey ( "raw" , rawKey , "AES-GCM" , false , [ "encrypt" ] ) ;
107
- const message_encoded = new TextEncoder ( ) . encode ( message ) ;
108
- const ciphertext_buffer = await window . crypto . subtle . encrypt (
109
- { name : "AES-GCM" , iv : iv } ,
110
- aes_key ,
111
- message_encoded
112
- ) ;
113
- const ciphertext = new Uint8Array ( ciphertext_buffer ) ;
114
- var iv_and_ciphertext = new Uint8Array ( iv . length + ciphertext . length ) ;
115
- iv_and_ciphertext . set ( iv , 0 ) ;
116
- iv_and_ciphertext . set ( ciphertext , iv . length ) ;
117
- return hex_encode ( iv_and_ciphertext ) ;
118
- }
103
+ const vetKey = encryptedVetKey . decryptAndVerify ( tsk , dpk , app_backend_principal . toUint8Array ( ) ) ;
119
104
120
- async function aes_gcm_decrypt ( ciphertext_hex , rawKey ) {
121
- const iv_and_ciphertext = hex_decode ( ciphertext_hex ) ;
122
- const iv = iv_and_ciphertext . subarray ( 0 , 12 ) ; // 96-bits; unique per message
123
- const ciphertext = iv_and_ciphertext . subarray ( 12 ) ;
124
- const aes_key = await window . crypto . subtle . importKey ( "raw" , rawKey , "AES-GCM" , false , [ "decrypt" ] ) ;
125
- let decrypted = await window . crypto . subtle . decrypt (
126
- { name : "AES-GCM" , iv : iv } ,
127
- aes_key ,
128
- ciphertext
129
- ) ;
130
- return new TextDecoder ( ) . decode ( decrypted ) ;
105
+ return await vetKey . asDerivedKeyMaterial ( ) ;
131
106
}
132
107
133
108
document . getElementById ( "ibe_encrypt_form" ) . addEventListener ( "submit" , async ( e ) => {
@@ -197,39 +172,42 @@ function update_ibe_decrypt_button_state() {
197
172
async function ibe_encrypt ( message ) {
198
173
document . getElementById ( "ibe_encrypt_result" ) . innerText = "Fetching IBE encryption key..."
199
174
const pk_bytes_hex = await app_backend_actor . ibe_encryption_key ( ) ;
175
+ const dpk = DerivedPublicKey . deserialize ( hex_decode ( pk_bytes_hex ) ) ;
200
176
201
177
document . getElementById ( "ibe_encrypt_result" ) . innerText = "Preparing IBE-encryption..."
202
178
const message_encoded = new TextEncoder ( ) . encode ( message ) ;
203
- const seed = window . crypto . getRandomValues ( new Uint8Array ( 32 ) ) ;
204
179
let ibe_principal = Principal . fromText ( document . getElementById ( "ibe_principal" ) . value ) ;
205
180
206
181
document . getElementById ( "ibe_encrypt_result" ) . innerText = "IBE-encrypting for principal" + ibe_principal . toText ( ) + "..." ;
207
- const ibe_ciphertext = vetkd . IBECiphertext . encrypt (
208
- hex_decode ( pk_bytes_hex ) ,
209
- ibe_principal . toUint8Array ( ) ,
182
+ const ibe_ciphertext = IbeCiphertext . encrypt (
183
+ dpk ,
184
+ IbeIdentity . fromPrincipal ( ibe_principal ) ,
210
185
message_encoded ,
211
- seed
186
+ IbeSeed . random ( ) ,
212
187
) ;
213
188
return hex_encode ( ibe_ciphertext . serialize ( ) ) ;
214
189
}
215
190
216
191
async function ibe_decrypt ( ibe_ciphertext_hex ) {
217
- document . getElementById ( "ibe_decrypt_result" ) . innerText = "Preparing IBE-decryption..."
218
- const tsk_seed = window . crypto . getRandomValues ( new Uint8Array ( 32 ) ) ;
219
- const tsk = new vetkd . TransportSecretKey ( tsk_seed ) ;
220
- document . getElementById ( "ibe_decrypt_result" ) . innerText = "Fetching IBE decryption key..."
221
- const ek_bytes_hex = await app_backend_actor . encrypted_ibe_decryption_key_for_caller ( tsk . public_key ( ) ) ;
222
192
document . getElementById ( "ibe_decrypt_result" ) . innerText = "Fetching IBE enryption key (needed for verification)..."
223
193
const pk_bytes_hex = await app_backend_actor . ibe_encryption_key ( ) ;
194
+ const dpk = DerivedPublicKey . deserialize ( hex_decode ( pk_bytes_hex ) ) ;
224
195
225
- const k_bytes = tsk . decrypt (
226
- hex_decode ( ek_bytes_hex ) ,
227
- hex_decode ( pk_bytes_hex ) ,
196
+ document . getElementById ( "ibe_decrypt_result" ) . innerText = "Fetching IBE decryption key..."
197
+ const tsk = TransportSecretKey . random ( ) ;
198
+ const ek_bytes_hex = await app_backend_actor . encrypted_ibe_decryption_key_for_caller ( tsk . publicKeyBytes ( ) ) ;
199
+ const encryptedVetKey = new EncryptedVetKey ( hex_decode ( ek_bytes_hex ) ) ;
200
+
201
+ document . getElementById ( "ibe_decrypt_result" ) . innerText = "Decrypting and verifying IBE decryption key..."
202
+ const vetKey = encryptedVetKey . decryptAndVerify (
203
+ tsk ,
204
+ dpk ,
228
205
app_backend_principal . toUint8Array ( )
229
206
) ;
230
207
231
- const ibe_ciphertext = vetkd . IBECiphertext . deserialize ( hex_decode ( ibe_ciphertext_hex ) ) ;
232
- const ibe_plaintext = ibe_ciphertext . decrypt ( k_bytes ) ;
208
+ document . getElementById ( "ibe_decrypt_result" ) . innerText = "Using IBE decryption key to decrypt ciphertext..."
209
+ const ibe_ciphertext = IbeCiphertext . deserialize ( hex_decode ( ibe_ciphertext_hex ) ) ;
210
+ const ibe_plaintext = ibe_ciphertext . decrypt ( vetKey ) ;
233
211
return new TextDecoder ( ) . decode ( ibe_plaintext ) ;
234
212
}
235
213
@@ -244,7 +222,7 @@ document.getElementById("login").onclick = async (e) => {
244
222
// Safari detection rules are according to: https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#browser_name_and_version
245
223
let isSafari = / ^ (? ! .* c h r o m e \/ \d + ) (? ! .* c h r o m i u m \/ \d + ) .* s a f a r i \/ \d + / i. test ( navigator . userAgent ) ;
246
224
let identityProvider = isSafari ?
247
- `http://localhost :4943/?canisterId=${ process . env . CANISTER_ID_INTERNET_IDENTITY } ` :
225
+ `http://127.0.0.1 :4943/?canisterId=${ process . env . CANISTER_ID_INTERNET_IDENTITY } ` :
248
226
`http://${ process . env . CANISTER_ID_INTERNET_IDENTITY } .localhost:4943/` ;
249
227
250
228
let authClient = await AuthClient . create ( ) ;
@@ -266,8 +244,8 @@ document.getElementById("login").onclick = async (e) => {
266
244
267
245
document . getElementById ( "principal" ) . innerHTML = annotated_principal ( app_backend_principal ) ;
268
246
269
- fetched_symmetric_key = null ;
270
- document . getElementById ( "get_symmetric_key_result " ) . innerText = "" ;
247
+ fetched_derived_key_material = null ;
248
+ document . getElementById ( "get_vetkey_result " ) . innerText = "" ;
271
249
update_plaintext_button_state ( ) ;
272
250
update_ciphertext_button_state ( ) ;
273
251
0 commit comments