Skip to content

Commit 5513fdc

Browse files
authored
Merge pull request #1119 from grafana/experimental/webcrypto
Document the k6/experimental/webcrypto module
2 parents afcde75 + 0b6cb72 commit 5513fdc

20 files changed

+1180
-0
lines changed

src/data/markdown/docs/02 javascript api/07 k6-experimental.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ excerpt: "k6 experimental APIs"
1111
| [redis](/javascript-api/k6-experimental/redis/) | Functionality to interact with [Redis](https://redis.io/). |
1212
| [timers](/javascript-api/k6-experimental/timers/) | `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval` |
1313
| [tracing](/javascript-api/k6-experimental/tracing/) | Support for instrumenting HTTP requests with tracing information. |
14+
| [webcrypto](/javascript-api/k6-experimental/webcrypto/) | Implements the [WebCrypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API). |
1415
| [websockets](/javascript-api/k6-experimental/websockets/) | Implements the browser's [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket). |
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---
2+
title: 'webcrypto'
3+
excerpt: "k6 webcrypto experimental API"
4+
---
5+
6+
<ExperimentalBlockquote />
7+
8+
With this experimental module, you can use the [WebCrypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) in your k6 scripts. However, note that this API is not yet fully implemented and some algorithms and features might still be missing.
9+
10+
The Web Crypto API is a JavaScript API for performing cryptographic operations such as encryption, decryption, digital signature generation and verification, and key generation and management. It provides a standard interface to access cryptographic functionality, which can help ensure that cryptographic operations are performed correctly and securely.
11+
12+
## API
13+
14+
The module exports a top-level `crypto` object with the following properties and methods:
15+
16+
| Interface/Function | Description |
17+
| :----------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
18+
| [getRandomValues](/javascript-api/k6-experimental/webcrypto/crypto/getrandomvalues) | Fills the passed `TypedArray` with cryptographically sound random values. |
19+
| [randomUUID](/javascript-api/k6-experimental/webcrypto/crypto/randomuuid) | Returns a randomly generated, 36 character long v4 UUID. |
20+
| [subtle](/javascript-api/k6-experimental/webcrypto/subtlecrypto) | The [SubtleCrypto](/javascript-api/k6-experimental/webcrypto/subtlecrypto) interface provides access to common cryptographic primitives, such as hashing, signing, encryption, or decryption. |
21+
22+
## Example
23+
24+
<CodeGroup labels={["example-webcrypto-module.js"]} lineNumbers={[]} showCopyButton={[true]}>
25+
26+
```javascript
27+
import { crypto } from "k6/experimental/webcrypto";
28+
29+
export default async function () {
30+
const plaintext = stringToArrayBuffer("Hello, World!");
31+
32+
/**
33+
* Generate a symmetric key using the AES-CBC algorithm.
34+
*/
35+
const key = await crypto.subtle.generateKey(
36+
{
37+
name: "AES-CBC",
38+
length: 256,
39+
},
40+
true,
41+
["encrypt", "decrypt"]
42+
);
43+
44+
/**
45+
* Encrypt the plaintext using the AES-CBC key with
46+
* have generated.
47+
*/
48+
const iv = crypto.getRandomValues(new Uint8Array(16));
49+
const ciphertext = await crypto.subtle.encrypt(
50+
{
51+
name: "AES-CBC",
52+
iv: iv,
53+
},
54+
key,
55+
plaintext
56+
);
57+
58+
/**
59+
* Decrypt the ciphertext using the same key to verify
60+
* that the resulting plaintext is the same as the original.
61+
*/
62+
const deciphered = await crypto.subtle.decrypt(
63+
{
64+
name: "AES-CBC",
65+
iv: iv,
66+
},
67+
key,
68+
ciphertext,
69+
);
70+
71+
console.log("deciphered text == original plaintext: ", arrayBufferToHex(deciphered) === arrayBufferToHex(plaintext))
72+
}
73+
74+
function arrayBufferToHex(buffer) {
75+
return [...new Uint8Array(buffer)]
76+
.map((x) => x.toString(16).padStart(2, "0"))
77+
.join("");
78+
}
79+
80+
function stringToArrayBuffer(str) {
81+
const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
82+
const bufView = new Uint16Array(buf);
83+
for (let i = 0, strLen = str.length; i < strLen; i++) {
84+
bufView[i] = str.charCodeAt(i);
85+
}
86+
return buf;
87+
}
88+
```
89+
90+
</CodeGroup>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
title: 'Crypto'
3+
excerpt: 'Crypto offers basic cryptography features.'
4+
---
5+
6+
`Crypto` allows access to a cryptographically strong random number generator and to cryptographic primitives.
7+
8+
## Properties
9+
10+
| Name | Type | Description |
11+
| :-------------- | :--------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------- |
12+
| `Crypto.subtle` | [SubtleCrypto](/javascript-api/k6-experimental/webcrypto/subtlecrypto) | The SubtleCrypto interface provides access to common cryptographic primitives, such as hashing, signing, encryption, or decryption. |
13+
14+
## Methods
15+
16+
| Name | Type | Description |
17+
| :--- | :--- | :---------- |
18+
| `Crypto.getRandomValues()` | [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBufferView) | Returns an array of cryptographically secure random values. |
19+
| `Crypto.randomUUID()` | [ArrayBuffer]() | Returns a randomly generated, 36 character long v4 UUID. |
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
title: 'getRandomValues'
3+
excerpt: 'getRandomValues fills the passed TypedArray with cryptographically sound random values.'
4+
---
5+
6+
The `getRandomValues()` method fills the passed `TypedArray` with cryptographically sound random values.
7+
8+
## Usage
9+
10+
```
11+
getRandomValues(typedArray)
12+
```
13+
14+
## Parameters
15+
16+
| Name | Type | Description |
17+
| :----------- | :----------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
18+
| `typedArray` | `TypedArray` | An integer-based `TypedArray` to fill with random values. Accepted `TypedArray` specific types are: `Int8Array`, `Uint8Array`, `Uint8ClampedArray`, `Int16Array`, `Uint16Array`, `Int32Array`, or `Uint32Array`. |
19+
20+
## Return Value
21+
22+
The same array is passed as the `typedArray` parameter with its contents replaced with the newly generated random numbers. The `typedArray` parameter is modified in place, and no copy is made.
23+
24+
## Throws
25+
26+
| Type | Description |
27+
| :------------------- | :------------------------------------------------------------------- |
28+
| `QuotaExceededError` | Thrown when `typedArray` is too large and its `byteLength` exceeds 65536. |
29+
30+
## Example
31+
32+
<CodeGroup labels={["example-webcrypto-getrandomvalues.js"]} lineNumbers={[]} showCopyButton={[true]}>
33+
34+
```javascript
35+
import { crypto } from "k6/experimental/webcrypto";
36+
37+
export default function () {
38+
const array = new Uint32Array(10);
39+
crypto.getRandomValues(array);
40+
41+
for (const num of array) {
42+
console.log(num);
43+
}
44+
}
45+
```
46+
47+
</CodeGroup>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
title: 'randomUUID'
3+
excerpt: 'randomUUID produces a 36-characters long string containing a cryptographically random UUID v4.'
4+
---
5+
6+
The `randomUUID` method produces a 36-characters long string that contains a cryptographically random UUID v4.
7+
8+
## Usage
9+
10+
```
11+
randomUUID()
12+
```
13+
14+
## Return Value
15+
16+
A string containing a 36-character cryptographically random UUID v4.
17+
18+
## Example
19+
20+
<CodeGroup labels={["example-webcrypto-randomuuid.js"]} lineNumbers={[]} showCopyButton={[true]}>
21+
22+
```javascript
23+
import { crypto } from "k6/experimental/webcrypto";
24+
25+
export default function () {
26+
const myUUID = crypto.randomUUID();
27+
28+
console.log(myUUID);
29+
}
30+
```
31+
32+
</CodeGroup>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
---
2+
title: 'SubtleCrypto'
3+
excerpt: 'SubtleCrypto offers low-level cryptographic functions.'
4+
---
5+
6+
The `SubtleCrypto` interface provides a set of low-level cryptographic primitives such as encryption, decryption, digital signature generation and verification, and key generation and management. It is useful for using secure and efficient cryptographic operations within k6 scripts.
7+
8+
## Methods
9+
10+
| Method | Description |
11+
| :-------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------ |
12+
| [encrypt](/javascript-api/k6-experimental/webcrypto/subtlecrypto/encrypt) | Encrypts the given plaintext data using the specified algorithm and key. |
13+
| [decrypt](/javascript-api/k6-experimental/webcrypto/subtlecrypto/decrypt) | Decrypts the given ciphertext data using the specified algorithm and key. |
14+
| [sign](/javascript-api/k6-experimental/webcrypto/subtlecrypto/sign) | Signs the given data using the specified algorithm and key. |
15+
| [verify](/javascript-api/k6-experimental/webcrypto/subtlecrypto/verify) | Verifies the signature of the given data using the specified algorithm and key. |
16+
| [digest](/javascript-api/k6-experimental/webcrypto/subtlecrypto/digest) | Computes the digest (hash) of the given data using the specified algorithm. |
17+
| [generateKey](/javascript-api/k6-experimental/webcrypto/subtlecrypto/generatekey) | Generates a new cryptographic key for use with the specified algorithm. |
18+
| [importKey](/javascript-api/k6-experimental/webcrypto/subtlecrypto/importkey) | Imports a raw key material into the Web Crypto API, generating a new key object to use with the specified algorithm.
19+
| [exportKey](/javascript-api/k6-experimental/webcrypto/subtlecrypto/exportkey) | Exports the raw key material of the given key object. |
20+
21+
## Example
22+
23+
<CodeGroup labels={["example-webcrypto-subtlecrypto.js"]} lineNumbers={[]} showCopyButton={[true]}>
24+
25+
```javascript
26+
import { crypto } from "k6/experimental/webcrypto";
27+
28+
export default async function () {
29+
const plaintext = stringToArrayBuffer("Hello, World!");
30+
31+
/**
32+
* Generate a symmetric key using the AES-CBC algorithm.
33+
*/
34+
const key = await crypto.subtle.generateKey(
35+
{
36+
name: "AES-CBC",
37+
length: 256,
38+
},
39+
true,
40+
["encrypt", "decrypt"]
41+
);
42+
43+
/**
44+
* Encrypt the plaintext using the AES-CBC key with
45+
* have generated.
46+
*/
47+
const iv = crypto.getRandomValues(new Uint8Array(16));
48+
const ciphertext = await crypto.subtle.encrypt(
49+
{
50+
name: "AES-CBC",
51+
iv: iv,
52+
},
53+
key,
54+
plaintext
55+
);
56+
57+
/**
58+
* Decrypt the ciphertext using the same key to verify
59+
* that the resulting plaintext is the same as the original.
60+
*/
61+
const deciphered = await crypto.subtle.decrypt(
62+
{
63+
name: "AES-CBC",
64+
iv: iv,
65+
},
66+
key,
67+
ciphertext,
68+
);
69+
70+
console.log("deciphered text == original plaintext: ", arrayBufferToHex(deciphered) === arrayBufferToHex(plaintext))
71+
}
72+
73+
function arrayBufferToHex(buffer) {
74+
return [...new Uint8Array(buffer)]
75+
.map((x) => x.toString(16).padStart(2, "0"))
76+
.join("");
77+
}
78+
79+
function stringToArrayBuffer(str) {
80+
const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
81+
const bufView = new Uint16Array(buf);
82+
for (let i = 0, strLen = str.length; i < strLen; i++) {
83+
bufView[i] = str.charCodeAt(i);
84+
}
85+
return buf;
86+
}
87+
```
88+
89+
</CodeGroup>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
---
2+
title: 'decrypt'
3+
excerpt: 'decrypt decrypts some encrypted data'
4+
---
5+
6+
The `decrypt()` method decrypts some encrypted data.
7+
8+
## Usage
9+
10+
```
11+
decrypt(algorithm, key, data)
12+
```
13+
14+
## Parameters
15+
16+
| Name | Type | Description |
17+
| :---------- | :--------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- |
18+
| `algorithm` | [AesCtrParams](/javascript-api/k6-experimental/webcrypto/aesctrparams), [AesCbcParams](/javascript-api/k6-experimental/webcrypto/aescbcparams), or [AesGcmParams](/javascript-api/k6-experimental/webcrypto/aesgcmparams) object | Defines the algorithm to use and any extra-parameters. The values given for the extra parameters must match those used in the corresponding [encrypt] call. |
19+
| `key` | [CryptoKey](/javascript-api/k6-experimental/webcrypto/cryptokey) | The [key](/javascript-api/k6-experimental/webcrypto/cryptokey) to use for decryption. |
20+
| `data` | `ArrayBuffer`, `TypedArray`, or `DataView` | The encrypted data to be decrypted (also known as _ciphertext_). |
21+
22+
## Return Value
23+
24+
A `Promise` that resolves to a new `ArrayBuffer` containing the decrypted data.
25+
26+
## Throws
27+
28+
| Type | Description |
29+
| :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
30+
| `InvalidAccessError` | Raised when the requested operation is not valid with the provided key. For instance when an invalid encryption algorithm is used, or a key not matching the selected algorithm is provided. |
31+
| `OperationError` | Raised when the operation failed for an operation-specific reason. For instance, if the algorithm size is invalid, or errors occurred during the process of decrypting the ciphertext. |
32+
33+
## Example
34+
35+
<CodeGroup labels={["example-webcrypto-decrypt.js"]} lineNumbers={[]} showCopyButton={[true]}>
36+
37+
```javascript
38+
import { crypto } from "k6/experimental/webcrypto";
39+
40+
export default async function () {
41+
const plaintext = stringToArrayBuffer("Hello, World!");
42+
43+
/**
44+
* Generate a symmetric key using the AES-CBC algorithm.
45+
*/
46+
const key = await crypto.subtle.generateKey(
47+
{
48+
name: "AES-CBC",
49+
length: 256,
50+
},
51+
true,
52+
["encrypt", "decrypt"]
53+
);
54+
55+
/**
56+
* Encrypt the plaintext using the AES-CBC key with
57+
* have generated.
58+
*/
59+
const iv = crypto.getRandomValues(new Uint8Array(16));
60+
const ciphertext = await crypto.subtle.encrypt(
61+
{
62+
name: "AES-CBC",
63+
iv: iv,
64+
},
65+
key,
66+
plaintext
67+
);
68+
69+
/**
70+
* Decrypt the ciphertext using the same key to verify
71+
* that the resulting plaintext is the same as the original.
72+
*/
73+
const deciphered = await crypto.subtle.decrypt(
74+
{
75+
name: "AES-CBC",
76+
iv: iv,
77+
},
78+
key,
79+
ciphertext,
80+
);
81+
82+
console.log("deciphered text == original plaintext: ", arrayBufferToHex(deciphered) === arrayBufferToHex(plaintext))
83+
}
84+
85+
function arrayBufferToHex(buffer) {
86+
return [...new Uint8Array(buffer)]
87+
.map((x) => x.toString(16).padStart(2, "0"))
88+
.join("");
89+
}
90+
91+
function stringToArrayBuffer(str) {
92+
const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
93+
const bufView = new Uint16Array(buf);
94+
for (let i = 0, strLen = str.length; i < strLen; i++) {
95+
bufView[i] = str.charCodeAt(i);
96+
}
97+
return buf;
98+
}
99+
```
100+
101+
</CodeGroup>

0 commit comments

Comments
 (0)