Skip to content

Commit

Permalink
Merge pull request #32 from grafana/feature/encrypt-decrypt-symmetric
Browse files Browse the repository at this point in the history
[3/3] Implement the `encrypt` and `decrypt` operations with support for AES algorithms
  • Loading branch information
oleiade authored Mar 29, 2023
2 parents ae80034 + 38c0660 commit ffddba3
Show file tree
Hide file tree
Showing 17 changed files with 2,005 additions and 93 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,21 @@ The current state of the project is that it is an experimental module of the Web
| `crypto.subtle.wrapKey()` || |
| `crypto.subtle.unwrapKey()` || |


### APIs and algorithms with limited support

- **AES-KW**: in the current state of things, this module does not support the AES-KW (JSON Key Wrap) algorithm. The reason for it is that the Go standard library does not support it. We are looking into alternatives, but for now, this is a limitation of the module.
- **AES-GCM**: although the algorithm is supported, and can already be used, it is not fully compliant with the specification. The reason for this is that the Go standard library only supports a 12-byte nonce/iv, while the specification allows for a wider range of sizes. We do not expect to address this limitation unless the Go standard library adds support for it.

## Contributing

Contributions are welcome!
Contributions are welcome! If the module is missing a feature you need, or if you find a bug, please open an issue or a pull request. If you are not sure about something, feel free to open an issue and ask.

### Practices

The [WebCrypto API specification](https://www.w3.org/TR/WebCryptoAPI) is quite large, and it is not always easy to understand what is going on. To help with that, we have adopted a few practices that we hope will make it easier for contributors to understand the codebase.

#### Algorithm steps numbered comments

Contributors will likely notice that the codebase is annotated with comments of the form `// {some number}.`. Those comments are used to track the progress of the implementation of the specification and to ensure the correctness of the implementation of the algorithms. The numbers are the section numbers of the specification. For example, the comment `// 8.` in the `SubtleCrypto.GenerateKey` function refers to [step 8 of the `generateKey` algorithm from the specification](https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey).

Following this convention allows us to document why certain operations are made in a certain way, and to track the progress of the implementation. We do not always add them, but we try to do so when it makes sense, and encourage contributors to do the same.
50 changes: 50 additions & 0 deletions examples/encrypt_decrypt/encrypt-decrypt-aes-cbc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { crypto } from "k6/x/webcrypto";

export default async function () {
const key = await crypto.subtle.generateKey(
{
name: "AES-CBC",
length: 256,
},
true,
["encrypt", "decrypt"]
);

const encoded = stringToArrayBuffer("Hello, World!");
const iv = crypto.getRandomValues(new Uint8Array(16));

const ciphertext = await crypto.subtle.encrypt(
{
name: "AES-CBC",
iv: iv,
},
key,
encoded
);

const plaintext = await crypto.subtle.decrypt(
{
name: "AES-CBC",
iv: iv,
},
key,
ciphertext,
);

console.log("deciphered text == original text: ", arrayBufferToHex(plaintext) === arrayBufferToHex(encoded))
}

function arrayBufferToHex(buffer) {
return [...new Uint8Array(buffer)]
.map((x) => x.toString(16).padStart(2, "0"))
.join("");
}

function stringToArrayBuffer(str) {
var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
52 changes: 52 additions & 0 deletions examples/encrypt_decrypt/encrypt-decrypt-aes-ctr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { crypto } from "k6/x/webcrypto";

export default async function () {
const key = await crypto.subtle.generateKey(
{
name: "AES-CTR",
length: 256,
},
true,
["encrypt", "decrypt"]
);

const encoded = string2ArrayBuffer("Hello World");
const counter = crypto.getRandomValues(new Uint8Array(16));

const ciphertext = await crypto.subtle.encrypt(
{
name: "AES-CTR",
counter,
length: 64,
},
key,
encoded
);

const plaintext = await crypto.subtle.decrypt(
{
name: "AES-CTR",
counter,
length: 64,
},
key,
ciphertext,
);

console.log("deciphered text == original text: ", arrayBufferToHex(plaintext) === arrayBufferToHex(encoded))
}

function arrayBufferToHex(buffer) {
return [...new Uint8Array(buffer)]
.map((x) => x.toString(16).padStart(2, "0"))
.join("");
}

function string2ArrayBuffer(str) {
var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
50 changes: 50 additions & 0 deletions examples/encrypt_decrypt/encrypt-decrypt-aes-gcm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { crypto } from "k6/x/webcrypto";

export default async function () {
const key = await crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 256,
},
true,
["encrypt", "decrypt"]
);

const encoded = string2ArrayBuffer("Hello World");
const iv = crypto.getRandomValues(new Uint8Array(12));

const ciphertext = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv,
},
key,
encoded
);

const plaintext = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv,
},
key,
ciphertext,
);

console.log("deciphered text == original text: ", arrayBufferToHex(plaintext) === arrayBufferToHex(encoded))
}

function arrayBufferToHex(buffer) {
return [...new Uint8Array(buffer)]
.map((x) => x.toString(16).padStart(2, "0"))
.join("");
}

function string2ArrayBuffer(str) {
var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
Loading

0 comments on commit ffddba3

Please sign in to comment.