Skip to content

Commit

Permalink
Merge pull request #3 from Open-Attestation/feat/unicode
Browse files Browse the repository at this point in the history
feat: encrypting unicode
  • Loading branch information
yehjxraymond authored Dec 16, 2019
2 parents acace8f + 7b779a6 commit e149cb1
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 27 deletions.
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ This library is used for encrypting OpenCerts files in transit
- [version](#version)
- [generateEncryptionKey](#generateencryptionkey)
- [Parameters](#parameters)
- [encodeDocument](#encodedocument)
- [Parameters](#parameters-1)
- [decodeDocument](#decodedocument)
- [Parameters](#parameters-2)
- [IEncryptionResults](#iencryptionresults)
- [encryptString](#encryptstring)
- [Parameters](#parameters-1)
- [Parameters](#parameters-3)
- [decryptString](#decryptstring)
- [Parameters](#parameters-2)
- [Parameters](#parameters-4)

### ENCRYPTION_PARAMETERS

Expand All @@ -45,6 +49,18 @@ Generates a random key represented as a hexadecimal string

- `keyLengthInBits` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** Key length (optional, default `ENCRYPTION_PARAMETERS.keyLength`)

### encodeDocument

#### Parameters

- `document` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**

### decodeDocument

#### Parameters

- `encoded` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**

### IEncryptionResults

### encryptString
Expand Down
52 changes: 48 additions & 4 deletions src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,37 @@
import { encryptString, decryptString, ENCRYPTION_PARAMETERS, IEncryptionResults } from ".";
import {
encryptString,
decryptString,
ENCRYPTION_PARAMETERS,
IEncryptionResults,
encodeDocument,
decodeDocument
} from ".";
import sample from "../test/fixture/sample.json";

const base64Regex = /^(?:[a-zA-Z0-9+/]{4})*(?:|(?:[a-zA-Z0-9+/]{3}=)|(?:[a-zA-Z0-9+/]{2}==)|(?:[a-zA-Z0-9+/]{1}===))$/;
const encryptionKeyRegex = new RegExp(`^[0-9a-f]{${ENCRYPTION_PARAMETERS.keyLength / 4}}$`);

describe("storage/crypto", () => {
it("should encrypt and decrypt unicode symbols correctly", () => {
const originalObject = JSON.stringify({ data: "Rating(≤ 25kg)" });
const enc = encryptString(originalObject);
const dec = decryptString(enc);
expect(dec).toStrictEqual(originalObject);
});

it("should encrypt and decrypt larger documents", () => {
const originalObject = JSON.stringify(sample);
const enc = encryptString(originalObject);
const dec = decryptString(enc);
expect(dec).toStrictEqual(originalObject);
});

describe("encryptString", () => {
let encryptionResults: any | IEncryptionResults;

test("should have the right keys and values when no key passed", async () => {
encryptionResults = encryptString("hello world");
expect(encryptionResults).toEqual(
expect(encryptionResults).toStrictEqual(
expect.objectContaining({
cipherText: expect.stringMatching(base64Regex),
iv: expect.stringMatching(base64Regex),
Expand All @@ -22,7 +44,7 @@ describe("storage/crypto", () => {
test("should have the right keys and values when key is passed", async () => {
const encryptionKey = "35fb46ca758889669f38c83d2f159b0f5a320b5a97387a9eaecb5652d15e0e3d";
encryptionResults = encryptString("hello world", encryptionKey);
expect(encryptionResults).toEqual(
expect(encryptionResults).toStrictEqual(
expect.objectContaining({
cipherText: expect.stringMatching(base64Regex),
iv: expect.stringMatching(base64Regex),
Expand All @@ -31,7 +53,7 @@ describe("storage/crypto", () => {
type: ENCRYPTION_PARAMETERS.version
})
);
expect(encryptionResults.key).toEqual(encryptionKey);
expect(encryptionResults.key).toStrictEqual(encryptionKey);
});
test("should throw error if input is not a string", () => {
encryptionResults = encryptString("hello world");
Expand All @@ -54,4 +76,26 @@ describe("storage/crypto", () => {
expect(decryptString(encryptionResults)).toBe("hello world");
});
});

describe("encodeDocument & decodeDocument", () => {
it("should do the reverse of each other", () => {
const input = "hello";
const encoded = encodeDocument(input);
const decoded = decodeDocument(encoded);
expect(decoded).toBe(input);
});

it("should work for unicode text", () => {
const input = "🦄😱|certificate|证书|sijil|प्रमाणपत्र";
const encoded = encodeDocument(input);
const decoded = decodeDocument(encoded);
expect(decoded).toBe(input);
});

it("encodeDocument should return url safe characters only", () => {
const input = "🦄😱|certificate|证书|sijil|प्रमाणपत्र";
const encoded = encodeDocument(input);
expect(encodeURI(encoded)).toBe(encoded);
});
});
});
20 changes: 14 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,17 @@ const makeCipher = (encryptionKey: string = generateEncryptionKey()) => {
return { cipher, encryptionKey, iv };
};

const preProcessDocument = (document: string) =>
// TODO: put compression in here?
forge.util.createBuffer(document);
export const encodeDocument = (document: string) => {
const bytes = forge.util.encodeUtf8(document);
const encoded = forge.util.encode64(bytes);
return encoded;
};

export const decodeDocument = (encoded: string) => {
const decoded = forge.util.decode64(encoded);
const document = forge.util.decodeUtf8(decoded);
return document;
};

export interface IEncryptionResults {
cipherText: string;
Expand All @@ -72,8 +80,8 @@ export const encryptString = (document: string, key?: string): IEncryptionResult
}

const { cipher, encryptionKey, iv } = makeCipher(key);

cipher.update(preProcessDocument(document));
const buffer = forge.util.createBuffer(encodeDocument(document));
cipher.update(buffer);
cipher.finish();

const encryptedMessage = forge.util.encode64(cipher.output.data);
Expand Down Expand Up @@ -115,5 +123,5 @@ export const decryptString = ({ cipherText, tag, iv, key, type }: IEncryptionRes
if (!success) {
throw new Error("Error decrypting message");
}
return decipher.output.data;
return decodeDocument(decipher.output.data);
};
60 changes: 60 additions & 0 deletions test/fixture/sample.json

Large diffs are not rendered by default.

32 changes: 17 additions & 15 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
{
"compilerOptions": {
"outDir": "dist/ts",
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"jsx": "react",
"strict": true,
"declaration": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"stripInternal": true
}
}
"compilerOptions": {
"outDir": "dist/ts",
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"jsx": "react",
"strict": true,
"declaration": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"stripInternal": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true
}
}

0 comments on commit e149cb1

Please sign in to comment.