Shaokang's Blog

In the real situation, information security is important and we may want to send encrypted text to user for their credential. It is good for validation and it can prevent some attack from user. Cloudflare worker has an implemented encode and decode feature, so it is possible to encrypt and deliver message to user via a constraint distributed system. The pointing system of https://capitaltwo.ga is built based on this. More details come below:

Details about different possible configuration could check official website at Web Crypto

Encode

Code as below, comment is the description of purpose of each line:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
async function encode(text, password) {
const iv = await crypto.getRandomValues(new Uint8Array(12)); //get a unique iv to encrypt

const myText = new TextEncoder().encode(text) // need TextEncoder to encode to buffer
const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(password), "AES-GCM", false, ["encrypt", "decrypt"]); //generate key, more details about configuration could be found on cloudflare worker official site
const myDigest = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv
},
key,
myText
)//the method to encrypt

const a = {
"iv": buffer2base(iv),//iv could be packaged and pass to user, they do not influence security
"text": buffer2base(myDigest)
}

return btoa(JSON.stringify(a));
}

In order to coded to a thing that could be delivered and saved in a normal text environment (in the last seven lines of the above coded), we can convert ArrayBuffer to Uint8Array and then use JSON.stringify to parse it. Like:

1
2
3
4
5
6
7
8
/**
*
* @param {arraybuffer object} buffer
*/
function buffer2base(buffer) {
return btoa(JSON.stringify(new Uint8Array(buffer)))

}

The encryption process is a Promise and should be handled with await

Decode

In order to decode, we need to recover generated base64 encoded text to normal buffer at first, like this:

1
2
3
4
5
6
7
/**
*
* @param {base64 object} code
*/
function base2buffer(code) {
return Uint8Array.from(Object.values(JSON.parse(atob(code)))).buffer
}

Other codes as below, comment is the description of purpose of each line:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
*
* @param {Text want to encrypt} text
* @param {password to decode} password
* @returns {decoded text}
*/
async function decode(encodeText, password) {
let a = JSON.parse(atob(encodeText)) //parse to get iv and the encoded text
const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(password), "AES-GCM", false, ["encrypt", "decrypt"]);//generate correct key buffer
const result = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: base2buffer(a.iv)
},
key,
base2buffer(a.text)
)//decode to get result, detailed configuration could check cloudflare website.

return new TextDecoder().decode(result);//Use TextDecoder to decode text to normal readable format.

}

Compare ArrayBuffer

The easiest way to compare is through compare the digit one by one, here is a sample:

1
2
3
4
5
6
7
8
9
function equal(buf1, buf2) {
if (buf1.byteLength != buf2.byteLength) return false;
var dv1 = new Int8Array(buf1);
var dv2 = new Int8Array(buf2);
for (var i = 0; i != buf1.byteLength; i++) {
if (dv1[i] != dv2[i]) return false;
}
return true;
}

 Comments