From de9f8867d5141940f47951c51648becec74959cb Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 21 Nov 2019 23:10:17 +0100 Subject: missing files / native encode/decode --- src/crypto/nativeCrypto-test.ts | 32 +++++++++ src/crypto/nativeCrypto.ts | 140 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 src/crypto/nativeCrypto-test.ts create mode 100644 src/crypto/nativeCrypto.ts (limited to 'src/crypto') diff --git a/src/crypto/nativeCrypto-test.ts b/src/crypto/nativeCrypto-test.ts new file mode 100644 index 000000000..7b9fcf256 --- /dev/null +++ b/src/crypto/nativeCrypto-test.ts @@ -0,0 +1,32 @@ +/* + This file is part of GNU Taler + (C) 2019 GNUnet e.V. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +/** + * Imports + */ +import test from "ava"; +import { encodeCrock, decodeCrock } from "./nativeCrypto"; + + +test("encoding", (t) => { + const utf8decoder = new TextDecoder("utf-8"); + const utf8encoder = new TextEncoder(); + const s = "Hello, World"; + const encStr = encodeCrock(utf8encoder.encode(s)); + const outBuf = decodeCrock(encStr); + const sOut = utf8decoder.decode(outBuf); + t.deepEqual(s, sOut); +}); \ No newline at end of file diff --git a/src/crypto/nativeCrypto.ts b/src/crypto/nativeCrypto.ts new file mode 100644 index 000000000..853ece6c7 --- /dev/null +++ b/src/crypto/nativeCrypto.ts @@ -0,0 +1,140 @@ +/* + This file is part of GNU Taler + (C) 2019 GNUnet e.V. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +/** + * Native implementation of GNU Taler crypto. + */ + +let isNode; + +let myGetRandom: (n: number) => ArrayBuffer; + +if (require) { + // node.js + const cr = require("crypto"); + myGetRandom = (n: number) => { + const buf = cr.randomBytes(n); + return Uint8Array.from(buf); + } +} else { + // Browser + myGetRandom = (n: number) => { + const ret = new Uint8Array(n); + window.crypto.getRandomValues(ret); + return ret; + } +} + +export function getRandomBytes(n: number): ArrayBuffer { + return myGetRandom(n); +} + +const encTable = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; + +class EncodingError extends Error { + constructor() { + super("Encoding error"); + Object.setPrototypeOf(this, EncodingError.prototype); + } +} + +function getValue(chr: string): number { + let a = chr; + switch (chr) { + case "O": + case "o": + a = "0;"; + break; + case "i": + case "I": + case "l": + case "L": + a = "1"; + break; + case "u": + case "U": + a = "V"; + } + + if (a >= "0" && a <= "9") { + return a.charCodeAt(0) - "0".charCodeAt(0); + } + + if (a >= "a" && a <= "z") a = a.toUpperCase(); + let dec = 0; + if (a >= "A" && a <= "Z") { + if ("I" < a) dec++; + if ("L" < a) dec++; + if ("O" < a) dec++; + if ("U" < a) dec++; + return a.charCodeAt(0) - "A".charCodeAt(0) + 10 - dec; + } + throw new EncodingError(); +} + +export function encodeCrock(data: ArrayBuffer): string { + const dataBytes = new Uint8Array(data); + let sb = ""; + const size = data.byteLength; + let bitBuf = 0; + let numBits = 0; + let pos = 0; + while (pos < size || numBits > 0) { + if (pos < size && numBits < 5) { + const d = dataBytes[pos++]; + bitBuf = (bitBuf << 8) | d; + numBits += 8; + } + if (numBits < 5) { + // zero-padding + bitBuf = bitBuf << (5 - numBits); + numBits = 5; + } + const v = (bitBuf >>> (numBits - 5)) & 31; + sb += encTable[v]; + numBits -= 5; + } + return sb; +} + +export function decodeCrock(encoded: string): ArrayBuffer { + const size = encoded.length; + let bitpos = 0; + let bitbuf = 0; + let readPosition = 0; + const outLen = Math.floor((size * 5) / 8); + const out = new Int8Array(outLen); + let outPos = 0; + + while (readPosition < size || bitpos > 0) { + //println("at position $readPosition with bitpos $bitpos") + if (readPosition < size) { + const v = getValue(encoded[readPosition++]); + bitbuf = (bitbuf << 5) | v; + bitpos += 5; + } + while (bitpos >= 8) { + const d = (bitbuf >>> (bitpos - 8)) & 0xff; + out[outPos++] = d; + bitpos -= 8; + } + if (readPosition == size && bitpos > 0) { + bitbuf = (bitbuf << (8 - bitpos)) & 0xff; + bitpos = bitbuf == 0 ? 0 : 8; + } + } + return out; +} -- cgit v1.2.3