├── .envrc ├── .github └── workflows │ └── luacheck.yml ├── .gitignore ├── .luacheckrc ├── .travis.yml ├── LICENSE ├── README.md ├── RunPerf.lua ├── RunTests.lua ├── lockbox.lua ├── lockbox ├── cipher │ ├── aes128.lua │ ├── aes192.lua │ ├── aes256.lua │ ├── des.lua │ ├── des3.lua │ ├── mode │ │ ├── cbc.lua │ │ ├── cfb.lua │ │ ├── ctr.lua │ │ ├── ecb.lua │ │ ├── ige.lua │ │ ├── ofb.lua │ │ └── pcbc.lua │ ├── tea.lua │ └── xtea.lua ├── digest │ ├── md2.lua │ ├── md4.lua │ ├── md5.lua │ ├── ripemd128.lua │ ├── ripemd160.lua │ ├── sha1.lua │ ├── sha2_224.lua │ └── sha2_256.lua ├── init.lua ├── kdf │ ├── hkdf.lua │ └── pbkdf2.lua ├── mac │ └── hmac.lua ├── padding │ ├── ansix923.lua │ ├── isoiec7816.lua │ ├── pkcs7.lua │ └── zero.lua └── util │ ├── array.lua │ ├── base64.lua │ ├── bit.lua │ ├── queue.lua │ └── stream.lua ├── rockspecs ├── lockbox-0.1.0-0.rockspec └── lockbox-scm-0.rockspec ├── script ├── bootstrap └── test └── test ├── AES128CipherTests.lua ├── AES192CipherTests.lua ├── AES256CipherTests.lua ├── Base64Tests.lua ├── DES3CipherTests.lua ├── DESCipherTests.lua ├── HKDFTests.lua ├── HMACTests.lua ├── MD2Tests.lua ├── MD4Tests.lua ├── MD5Tests.lua ├── PBKDF2Tests.lua ├── RIPEMD128Tests.lua ├── RIPEMD160Tests.lua ├── SHA1Tests.lua ├── SHA2_224Tests.lua ├── SHA2_256Tests.lua ├── TEACipherTests.lua └── XTEACipherTests.lua /.envrc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # TIP: Use https://github.com/direnv/direnv to automatically load this file. 3 | 4 | export PATH="$(pwd)/.env/bin:$PATH" 5 | -------------------------------------------------------------------------------- /.github/workflows/luacheck.yml: -------------------------------------------------------------------------------- 1 | name: Luacheck 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | luacheck: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v2 12 | - name: Setup Lua 13 | uses: leafo/gh-actions-lua@v8 14 | with: 15 | luaVersion: 5.3 16 | - name: Setup Lua Rocks 17 | uses: leafo/gh-actions-luarocks@v4 18 | - name: Setup dependencies 19 | run: luarocks install luacheck 20 | - name: Run Code Linter 21 | run: | 22 | luacheck . 23 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.env 2 | -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | include_files = { 2 | "**/*.lua" 3 | } 4 | 5 | exclude_files = { 6 | ".*/**/*.*", 7 | ".lua/bin/lua", 8 | ".lua/bin/luac", 9 | } 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: minimal 2 | env: 3 | - LUA_VERSION='lua-5.2' 4 | - LUA_VERSION='lua-5.3' 5 | - LUA_VERSION='luajit-2.0' 6 | matrix: 7 | allow_failures: 8 | - env: LUA_VERSION='lua-5.3' 9 | install: 10 | - script/bootstrap 11 | - source .envrc 12 | script: 13 | - script/test 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 James L. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | >## :information_source: Looking For Maintainers 2 | > 3 | >I'm afraid I've run out of free time to work on the Lockbox, so I'm looking for anyone interested in maintaining/growing the project. If you're interested, open an issue and request to be a collaborator. 4 | --- 5 | # The Lua Lockbox 6 | [![Build Status](https://travis-ci.com/somesocks/lua-lockbox.svg)](https://travis-ci.com/somesocks/lua-lockbox) [![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.png)](LICENSE) [![Luacheck](https://github.com/somesocks/lua-lockbox/workflows/Luacheck/badge.svg)](https://github.com/somesocks/lua-lockbox/actions) 7 | 8 | A collection of cryptographic primitives and protocols written in pure Lua. This was written to provide cross-platform, tested reference implementations of many different cryptographic primitives. These are written to be easy to read and easy to use, not for performance! 9 | 10 | # Implemented Primitives 11 | 12 | Digests: 13 | * MD2 14 | * MD4 15 | * MD5 16 | * RIPEMD128 17 | * RIPEMD160 18 | * SHA1 19 | * SHA2-224 20 | * SHA2-256 21 | 22 | Message Authentication Codes (MACs): 23 | * HMAC 24 | 25 | Key Derivation Functions (KDFs): 26 | * HKDF 27 | * PBKDF2 28 | 29 | Block Ciphers: 30 | * DES 31 | * DES3 32 | * AES128 33 | * AES192 34 | * AES256 35 | * TEA 36 | * XTEA 37 | 38 | Block Cipher Modes: 39 | * ECB 40 | * CBC 41 | * PCBC 42 | * CFB 43 | * OFB 44 | * CTR 45 | * IGE 46 | 47 | Block Cipher Padding: 48 | * Zero Padding 49 | * ANSI X.923 Padding 50 | * ISO/IEC 7816 Padding 51 | * PKCS7 Padding (PKCS5-Compatible) 52 | 53 | # Usage 54 | To use these cryptographic primitives in a project, you'll likely have to modify Lockbox.lua to change the module search path. All the primitives import this module to find the packages they require. See RunTests.lua as an example. 55 | 56 | The cryptographic primitives are designed to work on streams of bytes. There are three data structures used to help with this: Array(a Lua array of bytes), Stream(an iterator that returns a series of bytes), and Queue(a FIFO pipe of bytes). See Array.lua, Stream.lua, and Queue.lua for more details. 57 | 58 | Most cryptographic primitives are designed in a builder-style pattern. They usually have three functions: init, update, and finish. All of these functions will return the primitive, so you can chain functions calls together. 59 | 60 | * init() - resets the state of the primitive, so you can reuse it. 61 | * update( byteStream ) - takes in a Stream of bytes, and updates its internal state. This function can be called repeatedly, which effectively concatenates separate inputs. If the primitive requires an IV, it is usually read as the first input provided to update. 62 | * finish() - does any finalization necessary to finish generating output. 63 | 64 | For examples of how to use the different primitives, read the test case files under tests. 65 | 66 | # Security Concerns 67 | Several weak or broken primitives are implemented in this library, for research or legacy reasons. These should not be used under normal circumstances! To restrict their usage, they have been marked as insecure, with the Lockbox.insecure() method. This will cause a failed assertion when you attempt to import the module, unless you set Lockbox.ALLOW_INSECURE to true before the import. For an example, see RunTests.lua. 68 | 69 | # Modules names 70 | 71 | * `lockbox` (or `lockbox.init`) 72 | * `lockbox.cipher.aes128` 73 | * `lockbox.cipher.aes192` 74 | * `lockbox.cipher.aes256` 75 | * `lockbox.cipher.des3` 76 | * `lockbox.cipher.des` 77 | * `lockbox.cipher.mode.cbc` 78 | * `lockbox.cipher.mode.cfb` 79 | * `lockbox.cipher.mode.ctr` 80 | * `lockbox.cipher.mode.ecb` 81 | * `lockbox.cipher.mode.ige` 82 | * `lockbox.cipher.mode.ofb` 83 | * `lockbox.cipher.mode.pcbc` 84 | * `lockbox.digest.md2` 85 | * `lockbox.digest.md4` 86 | * `lockbox.digest.md5` 87 | * `lockbox.digest.ripemd128` 88 | * `lockbox.digest.ripemd160` 89 | * `lockbox.digest.sha1` 90 | * `lockbox.digest.sha2_224` 91 | * `lockbox.digest.sha2_256` 92 | * `lockbox.kdf.hkdf` 93 | * `lockbox.kdf.pbkdf2` 94 | * `lockbox.mac.hmac` 95 | * `lockbox.padding.ansix923` 96 | * `lockbox.padding.isoiec7816` 97 | * `lockbox.padding.pkcs7` 98 | * `lockbox.padding.zero` 99 | * `lockbox.util.base64` 100 | * `lockbox.util.array` 101 | * `lockbox.util.bit` 102 | * `lockbox.util.queue` 103 | * `lockbox.util.stream` 104 | 105 | # Planned Updates 106 | * RC4 107 | * XXTEA 108 | * SHA3(Keccak) 109 | * MD6 110 | * BLAKE2s 111 | * bcrypt / scrypt 112 | 113 | -------------------------------------------------------------------------------- /RunPerf.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Lockbox - crude performance tests 3 | 4 | Based off of test_perf.lua from https://github.com/philanc/plc 5 | Modified to work with Lockbox's API. 6 | ]] 7 | 8 | 9 | local Lockbox = require("lockbox") 10 | Lockbox.ALLOW_INSECURE = true 11 | ------------------------------------------------------------ 12 | 13 | local Stream = require("lockbox.util.stream") 14 | local Array = require("lockbox.util.array") 15 | 16 | ------------------------------------------------------------ 17 | 18 | local function pf(...) print(string.format(...)) end 19 | 20 | local start, done do 21 | local c0, desc, cmt 22 | start = function (d, c) 23 | desc = d 24 | cmt = c and "-- " .. c or "" --optional comment 25 | c0 = os.clock() 26 | end 27 | done = function () 28 | local dc = os.clock() - c0 29 | pf("- %-30s %7.1f %s", desc, dc, cmt) 30 | end 31 | end 32 | 33 | 34 | local sizemb = 1 -- plain text size (in MBytes) 35 | local mega = 1024 * 1024 36 | local size = mega * sizemb 37 | local plain = ('a'):rep(size) 38 | local k8 = ('k'):rep(8) 39 | local k16 = k8:rep(2) 40 | local k32 = k16:rep(2) 41 | local iv8 = ('i'):rep(8) 42 | local iv16 = iv8:rep(2) 43 | local iv32 = iv16:rep(2) 44 | 45 | ------------------------------------------------------------ 46 | 47 | local function perf_digest(dig) 48 | local algo = require ("lockbox.digest." .. dig) 49 | local m = plain 50 | 51 | start(dig) 52 | algo().update( Stream.fromString(m) ).finish() 53 | done() 54 | end 55 | 56 | ------------------------------------------------------------ 57 | 58 | local function perf_hmacdigest(dig) 59 | local hmac = require ("lockbox.mac.hmac") 60 | local algo = require ("lockbox.digest." .. dig) 61 | 62 | local key = Array.fromString(k16) 63 | 64 | local m = plain 65 | 66 | start("hmac_" .. dig) 67 | hmac = hmac().setBlockSize(64).setDigest(algo).setKey(key) 68 | hmac.update( Stream.fromString(m) ).finish() 69 | done() 70 | end 71 | 72 | ------------------------------------------------------------ 73 | 74 | local function perf_blockcipher(algo, mode, padding, params) 75 | local desc = string.format("%s_%s + %sPad", algo, mode, padding) 76 | mode = require ("lockbox.cipher.mode." .. mode) 77 | algo = require ("lockbox.cipher." .. algo) 78 | padding = require ("lockbox.padding." .. padding) 79 | 80 | params = params or {} 81 | params.key = params.key or k16 82 | params.iv = params.iv or iv16 83 | 84 | local key = Array.fromString(params.key) 85 | local iv = Array.fromString(params.iv) 86 | 87 | local m = not params.downscale 88 | and plain 89 | or plain:sub(1, math.min(size, size * params.downscale)) 90 | local ciphertext 91 | 92 | start(desc .. " encrypt", #m ~= #plain and #m .. " bytes") 93 | local cipher = mode.Cipher() 94 | .setBlockCipher(algo) 95 | .setPadding(padding) 96 | .setKey(key) 97 | 98 | ciphertext = cipher.init() 99 | .update( Stream.fromArray( iv ) ) 100 | .update( Stream.fromHex(m) ) 101 | .finish() 102 | .asHex() 103 | :lower() 104 | done() 105 | 106 | start(desc .. " decrypt", #m ~= #plain and #m .. " bytes") 107 | local decipher = mode.Decipher() 108 | .setBlockCipher(algo) 109 | .setPadding(padding) 110 | .setKey(key) 111 | 112 | local plaintext = decipher.init() 113 | .update( Stream.fromArray( iv ) ) 114 | .update( Stream.fromHex(ciphertext) ) 115 | .finish() 116 | .asHex() 117 | :lower() 118 | done() 119 | 120 | assert(plaintext == m, plaintext .. ' ~= ' .. m) 121 | end 122 | 123 | ------------------------------------------------------------ 124 | 125 | local function perf_base(base) 126 | local base_n = require ("lockbox.util." .. base) 127 | 128 | local m = plain 129 | local encoded, decoded 130 | 131 | start(base .. " encoding") 132 | encoded = base_n.fromString(m) 133 | done() 134 | 135 | start(base .. " decoding") 136 | decoded = base_n.toString(encoded) 137 | done() 138 | 139 | assert(decoded == m) 140 | end 141 | 142 | ------------------------------------------------------------ 143 | 144 | print(_VERSION) 145 | 146 | pf("Plain text: %d MBytes except where noted", sizemb) 147 | pf("Elapsed time in seconds") 148 | 149 | print("\n-- hash digest \n") 150 | 151 | perf_digest "md2" 152 | perf_digest "md4" 153 | perf_digest "md5" 154 | perf_digest "sha1" 155 | perf_digest "sha2_224" 156 | perf_digest "sha2_256" 157 | perf_digest "ripemd128" 158 | perf_digest "ripemd160" 159 | 160 | print("\n-- hmac digest \n") 161 | 162 | perf_hmacdigest "md5" 163 | perf_hmacdigest "sha1" 164 | perf_hmacdigest "sha2_224" 165 | perf_hmacdigest "sha2_256" 166 | 167 | print("\n-- block cipher \n") 168 | 169 | perf_blockcipher ("des", "ecb", "zero", { key = k8, iv = "", downscale = 2^-4 }) 170 | perf_blockcipher ("des", "cbc", "zero", { key = k8, iv = iv8, downscale = 2^-4 }) 171 | 172 | perf_blockcipher ("aes128", "ecb", "zero", { iv = "", downscale = 2^-2 }) 173 | perf_blockcipher ("aes128", "cbc", "zero", { downscale = 2^-2 }) 174 | perf_blockcipher ("aes128", "cfb", "zero", { downscale = 2^-2 }) 175 | perf_blockcipher ("aes128", "ofb", "zero", { downscale = 2^-2 }) 176 | perf_blockcipher ("aes128", "ctr", "zero", { downscale = 2^-2 }) 177 | perf_blockcipher ("aes128", "ige", "zero", { iv = iv32, downscale = 2^-2 }) 178 | perf_blockcipher ("aes128", "cbc", "pkcs7", { downscale = 2^-2 }) 179 | 180 | perf_blockcipher ("aes256", "cbc", "zero", { key = k32, downscale = 2^-2 }) 181 | perf_blockcipher ("aes256", "ctr", "zero", { key = k32, downscale = 2^-2 }) 182 | 183 | perf_blockcipher ("tea", "ecb", "zero", { iv = "" }) 184 | perf_blockcipher ("tea", "cbc", "zero", { iv = iv8 }) 185 | perf_blockcipher ("xtea", "ecb", "zero", { iv = "" }) 186 | perf_blockcipher ("xtea", "cbc", "zero", { iv = iv8 }) 187 | 188 | print("\n-- base encoding \n") 189 | 190 | perf_base "base64" 191 | -------------------------------------------------------------------------------- /RunTests.lua: -------------------------------------------------------------------------------- 1 | local String = require("string"); 2 | local Lockbox = require("lockbox"); 3 | 4 | Lockbox.ALLOW_INSECURE = true; 5 | 6 | local tests = { 7 | "Base64Tests", 8 | "MD2Tests", 9 | "MD4Tests", 10 | "MD5Tests", 11 | "RIPEMD128Tests", 12 | "RIPEMD160Tests", 13 | "SHA1Tests", 14 | "SHA2_224Tests", 15 | "SHA2_256Tests", 16 | "HMACTests", 17 | "HKDFTests", 18 | "PBKDF2Tests", 19 | "DESCipherTests", 20 | "DES3CipherTests", 21 | "AES128CipherTests", 22 | "AES192CipherTests", 23 | "AES256CipherTests", 24 | "TEACipherTests", 25 | "XTEACipherTests", 26 | }; 27 | 28 | local status = 0 29 | 30 | for _, v in pairs(tests) do 31 | print(String.format("Running %s...", v)); 32 | local ok, err = pcall(require, "test." .. v); 33 | if not ok then 34 | print(String.format("FAIL: %s failed with error:\n%s\n", v, err)); 35 | status = 1 36 | else 37 | print(String.format("%s passed!\n", v)); 38 | end 39 | end 40 | 41 | os.exit(status, true) 42 | -------------------------------------------------------------------------------- /lockbox.lua: -------------------------------------------------------------------------------- 1 | return require("lockbox.init") 2 | -------------------------------------------------------------------------------- /lockbox/cipher/des3.lua: -------------------------------------------------------------------------------- 1 | require("lockbox").insecure(); 2 | 3 | local Array = require("lockbox.util.array"); 4 | 5 | local DES = require("lockbox.cipher.des"); 6 | 7 | local DES3 = {}; 8 | 9 | local getKeys = function(keyBlock) 10 | local size = Array.size(keyBlock) 11 | 12 | local key1; 13 | local key2; 14 | local key3; 15 | 16 | if (size == 8) then 17 | key1 = keyBlock; 18 | key2 = keyBlock; 19 | key3 = keyBlock; 20 | elseif (size == 16) then 21 | key1 = Array.slice(keyBlock, 1, 8); 22 | key2 = Array.slice(keyBlock, 9, 16); 23 | key3 = key1; 24 | elseif (size == 24) then 25 | key1 = Array.slice(keyBlock, 1, 8); 26 | key2 = Array.slice(keyBlock, 9, 16); 27 | key3 = Array.slice(keyBlock, 17, 24); 28 | else 29 | assert(false, "Invalid key size for 3DES"); 30 | end 31 | 32 | return key1, key2, key3; 33 | end 34 | 35 | DES3.blockSize = DES.blockSize; 36 | 37 | DES3.encrypt = function(keyBlock, inputBlock) 38 | local key1; 39 | local key2; 40 | local key3; 41 | 42 | key1, key2, key3 = getKeys(keyBlock); 43 | 44 | local block = inputBlock; 45 | block = DES.encrypt(key1, block); 46 | block = DES.decrypt(key2, block); 47 | block = DES.encrypt(key3, block); 48 | 49 | return block; 50 | end 51 | 52 | DES3.decrypt = function(keyBlock, inputBlock) 53 | local key1; 54 | local key2; 55 | local key3; 56 | 57 | key1, key2, key3 = getKeys(keyBlock); 58 | 59 | local block = inputBlock; 60 | block = DES.decrypt(key3, block); 61 | block = DES.encrypt(key2, block); 62 | block = DES.decrypt(key1, block); 63 | 64 | return block; 65 | end 66 | 67 | return DES3; 68 | -------------------------------------------------------------------------------- /lockbox/cipher/mode/cbc.lua: -------------------------------------------------------------------------------- 1 | local Array = require("lockbox.util.array"); 2 | local Stream = require("lockbox.util.stream"); 3 | local Queue = require("lockbox.util.queue"); 4 | 5 | local CBC = {}; 6 | 7 | CBC.Cipher = function() 8 | 9 | local public = {}; 10 | 11 | local key; 12 | local blockCipher; 13 | local padding; 14 | local inputQueue; 15 | local outputQueue; 16 | local iv; 17 | 18 | public.setKey = function(keyBytes) 19 | key = keyBytes; 20 | return public; 21 | end 22 | 23 | public.setBlockCipher = function(cipher) 24 | blockCipher = cipher; 25 | return public; 26 | end 27 | 28 | public.setPadding = function(paddingMode) 29 | padding = paddingMode; 30 | return public; 31 | end 32 | 33 | public.init = function() 34 | inputQueue = Queue(); 35 | outputQueue = Queue(); 36 | iv = nil; 37 | return public; 38 | end 39 | 40 | public.update = function(messageStream) 41 | local byte = messageStream(); 42 | while (byte ~= nil) do 43 | inputQueue.push(byte); 44 | if(inputQueue.size() >= blockCipher.blockSize) then 45 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 46 | 47 | if(iv == nil) then 48 | iv = block; 49 | else 50 | local out = Array.XOR(iv, block); 51 | out = blockCipher.encrypt(key, out); 52 | Array.writeToQueue(outputQueue, out); 53 | iv = out; 54 | end 55 | end 56 | byte = messageStream(); 57 | end 58 | return public; 59 | end 60 | 61 | public.finish = function() 62 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 63 | public.update(paddingStream); 64 | 65 | return public; 66 | end 67 | 68 | public.getOutputQueue = function() 69 | return outputQueue; 70 | end 71 | 72 | public.asHex = function() 73 | return Stream.toHex(outputQueue.pop); 74 | end 75 | 76 | public.asBytes = function() 77 | return Stream.toArray(outputQueue.pop); 78 | end 79 | 80 | public.asString = function() 81 | return Stream.toString(outputQueue.pop); 82 | end 83 | 84 | return public; 85 | 86 | end 87 | 88 | 89 | CBC.Decipher = function() 90 | 91 | local public = {}; 92 | 93 | local key; 94 | local blockCipher; 95 | local padding; 96 | local inputQueue; 97 | local outputQueue; 98 | local iv; 99 | 100 | public.setKey = function(keyBytes) 101 | key = keyBytes; 102 | return public; 103 | end 104 | 105 | public.setBlockCipher = function(cipher) 106 | blockCipher = cipher; 107 | return public; 108 | end 109 | 110 | public.setPadding = function(paddingMode) 111 | padding = paddingMode; 112 | return public; 113 | end 114 | 115 | public.init = function() 116 | inputQueue = Queue(); 117 | outputQueue = Queue(); 118 | iv = nil; 119 | return public; 120 | end 121 | 122 | public.update = function(messageStream) 123 | local byte = messageStream(); 124 | while (byte ~= nil) do 125 | inputQueue.push(byte); 126 | if(inputQueue.size() >= blockCipher.blockSize) then 127 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 128 | 129 | if(iv == nil) then 130 | iv = block; 131 | else 132 | local out = block; 133 | out = blockCipher.decrypt(key, out); 134 | out = Array.XOR(iv, out); 135 | Array.writeToQueue(outputQueue, out); 136 | iv = block; 137 | end 138 | end 139 | byte = messageStream(); 140 | end 141 | return public; 142 | end 143 | 144 | public.finish = function() 145 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 146 | public.update(paddingStream); 147 | 148 | return public; 149 | end 150 | 151 | public.getOutputQueue = function() 152 | return outputQueue; 153 | end 154 | 155 | public.asHex = function() 156 | return Stream.toHex(outputQueue.pop); 157 | end 158 | 159 | public.asBytes = function() 160 | return Stream.toArray(outputQueue.pop); 161 | end 162 | 163 | public.asString = function() 164 | return Stream.toString(outputQueue.pop); 165 | end 166 | 167 | return public; 168 | 169 | end 170 | 171 | return CBC; 172 | 173 | -------------------------------------------------------------------------------- /lockbox/cipher/mode/cfb.lua: -------------------------------------------------------------------------------- 1 | local Array = require("lockbox.util.array"); 2 | local Stream = require("lockbox.util.stream"); 3 | local Queue = require("lockbox.util.queue"); 4 | 5 | local CFB = {}; 6 | 7 | CFB.Cipher = function() 8 | 9 | local public = {}; 10 | 11 | local key; 12 | local blockCipher; 13 | local padding; 14 | local inputQueue; 15 | local outputQueue; 16 | local iv; 17 | 18 | public.setKey = function(keyBytes) 19 | key = keyBytes; 20 | return public; 21 | end 22 | 23 | public.setBlockCipher = function(cipher) 24 | blockCipher = cipher; 25 | return public; 26 | end 27 | 28 | public.setPadding = function(paddingMode) 29 | padding = paddingMode; 30 | return public; 31 | end 32 | 33 | public.init = function() 34 | inputQueue = Queue(); 35 | outputQueue = Queue(); 36 | iv = nil; 37 | return public; 38 | end 39 | 40 | public.update = function(messageStream) 41 | local byte = messageStream(); 42 | while (byte ~= nil) do 43 | inputQueue.push(byte); 44 | if(inputQueue.size() >= blockCipher.blockSize) then 45 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 46 | 47 | if(iv == nil) then 48 | iv = block; 49 | else 50 | local out = iv; 51 | out = blockCipher.encrypt(key, out); 52 | out = Array.XOR(out, block); 53 | Array.writeToQueue(outputQueue, out); 54 | iv = out; 55 | end 56 | end 57 | byte = messageStream(); 58 | end 59 | return public; 60 | end 61 | 62 | public.finish = function() 63 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 64 | public.update(paddingStream); 65 | 66 | return public; 67 | end 68 | 69 | public.getOutputQueue = function() 70 | return outputQueue; 71 | end 72 | 73 | public.asHex = function() 74 | return Stream.toHex(outputQueue.pop); 75 | end 76 | 77 | public.asBytes = function() 78 | return Stream.toArray(outputQueue.pop); 79 | end 80 | 81 | public.asString = function() 82 | return Stream.toString(outputQueue.pop); 83 | end 84 | 85 | return public; 86 | 87 | end 88 | 89 | CFB.Decipher = function() 90 | 91 | local public = {}; 92 | 93 | local key; 94 | local blockCipher; 95 | local padding; 96 | local inputQueue; 97 | local outputQueue; 98 | local iv; 99 | 100 | public.setKey = function(keyBytes) 101 | key = keyBytes; 102 | return public; 103 | end 104 | 105 | public.setBlockCipher = function(cipher) 106 | blockCipher = cipher; 107 | return public; 108 | end 109 | 110 | public.setPadding = function(paddingMode) 111 | padding = paddingMode; 112 | return public; 113 | end 114 | 115 | public.init = function() 116 | inputQueue = Queue(); 117 | outputQueue = Queue(); 118 | iv = nil; 119 | return public; 120 | end 121 | 122 | public.update = function(messageStream) 123 | local byte = messageStream(); 124 | while (byte ~= nil) do 125 | inputQueue.push(byte); 126 | if(inputQueue.size() >= blockCipher.blockSize) then 127 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 128 | 129 | if(iv == nil) then 130 | iv = block; 131 | else 132 | local out = iv; 133 | out = blockCipher.encrypt(key, out); 134 | out = Array.XOR(out, block); 135 | Array.writeToQueue(outputQueue, out); 136 | iv = block; 137 | end 138 | end 139 | byte = messageStream(); 140 | end 141 | return public; 142 | end 143 | 144 | public.finish = function() 145 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 146 | public.update(paddingStream); 147 | 148 | return public; 149 | end 150 | 151 | public.getOutputQueue = function() 152 | return outputQueue; 153 | end 154 | 155 | public.asHex = function() 156 | return Stream.toHex(outputQueue.pop); 157 | end 158 | 159 | public.asBytes = function() 160 | return Stream.toArray(outputQueue.pop); 161 | end 162 | 163 | public.asString = function() 164 | return Stream.toString(outputQueue.pop); 165 | end 166 | 167 | return public; 168 | 169 | end 170 | 171 | return CFB; 172 | -------------------------------------------------------------------------------- /lockbox/cipher/mode/ctr.lua: -------------------------------------------------------------------------------- 1 | local Array = require("lockbox.util.array"); 2 | local Stream = require("lockbox.util.stream"); 3 | local Queue = require("lockbox.util.queue"); 4 | 5 | local Bit = require("lockbox.util.bit"); 6 | 7 | local AND = Bit.band; 8 | 9 | local CTR = {}; 10 | 11 | CTR.Cipher = function() 12 | 13 | local public = {}; 14 | 15 | local key; 16 | local blockCipher; 17 | local padding; 18 | local inputQueue; 19 | local outputQueue; 20 | local iv; 21 | 22 | public.setKey = function(keyBytes) 23 | key = keyBytes; 24 | return public; 25 | end 26 | 27 | public.setBlockCipher = function(cipher) 28 | blockCipher = cipher; 29 | return public; 30 | end 31 | 32 | public.setPadding = function(paddingMode) 33 | padding = paddingMode; 34 | return public; 35 | end 36 | 37 | public.init = function() 38 | inputQueue = Queue(); 39 | outputQueue = Queue(); 40 | iv = nil; 41 | return public; 42 | end 43 | 44 | local updateIV = function() 45 | iv[16] = iv[16] + 1; 46 | if iv[16] <= 0xFF then return; end 47 | iv[16] = AND(iv[16], 0xFF); 48 | 49 | iv[15] = iv[15] + 1; 50 | if iv[15] <= 0xFF then return; end 51 | iv[15] = AND(iv[15], 0xFF); 52 | 53 | iv[14] = iv[14] + 1; 54 | if iv[14] <= 0xFF then return; end 55 | iv[14] = AND(iv[14], 0xFF); 56 | 57 | iv[13] = iv[13] + 1; 58 | if iv[13] <= 0xFF then return; end 59 | iv[13] = AND(iv[13], 0xFF); 60 | 61 | iv[12] = iv[12] + 1; 62 | if iv[12] <= 0xFF then return; end 63 | iv[12] = AND(iv[12], 0xFF); 64 | 65 | iv[11] = iv[11] + 1; 66 | if iv[11] <= 0xFF then return; end 67 | iv[11] = AND(iv[11], 0xFF); 68 | 69 | iv[10] = iv[10] + 1; 70 | if iv[10] <= 0xFF then return; end 71 | iv[10] = AND(iv[10], 0xFF); 72 | 73 | iv[9] = iv[9] + 1; 74 | if iv[9] <= 0xFF then return; end 75 | iv[9] = AND(iv[9], 0xFF); 76 | 77 | return; 78 | end 79 | 80 | public.update = function(messageStream) 81 | local byte = messageStream(); 82 | while (byte ~= nil) do 83 | inputQueue.push(byte); 84 | 85 | if(inputQueue.size() >= blockCipher.blockSize) then 86 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 87 | 88 | if(iv == nil) then 89 | iv = block; 90 | else 91 | local out = iv; 92 | out = blockCipher.encrypt(key, out); 93 | 94 | out = Array.XOR(out, block); 95 | Array.writeToQueue(outputQueue, out); 96 | updateIV(); 97 | end 98 | end 99 | byte = messageStream(); 100 | end 101 | return public; 102 | end 103 | 104 | public.finish = function() 105 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 106 | public.update(paddingStream); 107 | 108 | return public; 109 | end 110 | 111 | public.getOutputQueue = function() 112 | return outputQueue; 113 | end 114 | 115 | public.asHex = function() 116 | return Stream.toHex(outputQueue.pop); 117 | end 118 | 119 | public.asBytes = function() 120 | return Stream.toArray(outputQueue.pop); 121 | end 122 | 123 | public.asString = function() 124 | return Stream.toString(outputQueue.pop); 125 | end 126 | 127 | return public; 128 | 129 | end 130 | 131 | 132 | CTR.Decipher = function() 133 | 134 | local public = {}; 135 | 136 | local key; 137 | local blockCipher; 138 | local padding; 139 | local inputQueue; 140 | local outputQueue; 141 | local iv; 142 | 143 | public.setKey = function(keyBytes) 144 | key = keyBytes; 145 | return public; 146 | end 147 | 148 | public.setBlockCipher = function(cipher) 149 | blockCipher = cipher; 150 | return public; 151 | end 152 | 153 | public.setPadding = function(paddingMode) 154 | padding = paddingMode; 155 | return public; 156 | end 157 | 158 | public.init = function() 159 | inputQueue = Queue(); 160 | outputQueue = Queue(); 161 | iv = nil; 162 | return public; 163 | end 164 | 165 | local updateIV = function() 166 | iv[16] = iv[16] + 1; 167 | if iv[16] <= 0xFF then return; end 168 | iv[16] = AND(iv[16], 0xFF); 169 | 170 | iv[15] = iv[15] + 1; 171 | if iv[15] <= 0xFF then return; end 172 | iv[15] = AND(iv[15], 0xFF); 173 | 174 | iv[14] = iv[14] + 1; 175 | if iv[14] <= 0xFF then return; end 176 | iv[14] = AND(iv[14], 0xFF); 177 | 178 | iv[13] = iv[13] + 1; 179 | if iv[13] <= 0xFF then return; end 180 | iv[13] = AND(iv[13], 0xFF); 181 | 182 | iv[12] = iv[12] + 1; 183 | if iv[12] <= 0xFF then return; end 184 | iv[12] = AND(iv[12], 0xFF); 185 | 186 | iv[11] = iv[11] + 1; 187 | if iv[11] <= 0xFF then return; end 188 | iv[11] = AND(iv[11], 0xFF); 189 | 190 | iv[10] = iv[10] + 1; 191 | if iv[10] <= 0xFF then return; end 192 | iv[10] = AND(iv[10], 0xFF); 193 | 194 | iv[9] = iv[9] + 1; 195 | if iv[9] <= 0xFF then return; end 196 | iv[9] = AND(iv[9], 0xFF); 197 | 198 | return; 199 | end 200 | 201 | public.update = function(messageStream) 202 | local byte = messageStream(); 203 | while (byte ~= nil) do 204 | inputQueue.push(byte); 205 | 206 | if(inputQueue.size() >= blockCipher.blockSize) then 207 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 208 | 209 | if(iv == nil) then 210 | iv = block; 211 | else 212 | local out = iv; 213 | out = blockCipher.encrypt(key, out); 214 | 215 | out = Array.XOR(out, block); 216 | Array.writeToQueue(outputQueue, out); 217 | updateIV(); 218 | end 219 | end 220 | byte = messageStream(); 221 | end 222 | return public; 223 | end 224 | 225 | public.finish = function() 226 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 227 | public.update(paddingStream); 228 | 229 | return public; 230 | end 231 | 232 | public.getOutputQueue = function() 233 | return outputQueue; 234 | end 235 | 236 | public.asHex = function() 237 | return Stream.toHex(outputQueue.pop); 238 | end 239 | 240 | public.asBytes = function() 241 | return Stream.toArray(outputQueue.pop); 242 | end 243 | 244 | public.asString = function() 245 | return Stream.toString(outputQueue.pop); 246 | end 247 | 248 | return public; 249 | 250 | end 251 | 252 | 253 | 254 | 255 | return CTR; 256 | 257 | -------------------------------------------------------------------------------- /lockbox/cipher/mode/ecb.lua: -------------------------------------------------------------------------------- 1 | require("lockbox").insecure(); 2 | 3 | local Array = require("lockbox.util.array"); 4 | local Stream = require("lockbox.util.stream"); 5 | local Queue = require("lockbox.util.queue"); 6 | 7 | local ECB = {}; 8 | 9 | ECB.Cipher = function() 10 | 11 | local public = {}; 12 | 13 | local key; 14 | local blockCipher; 15 | local padding; 16 | local inputQueue; 17 | local outputQueue; 18 | 19 | public.setKey = function(keyBytes) 20 | key = keyBytes; 21 | return public; 22 | end 23 | 24 | public.setBlockCipher = function(cipher) 25 | blockCipher = cipher; 26 | return public; 27 | end 28 | 29 | public.setPadding = function(paddingMode) 30 | padding = paddingMode; 31 | return public; 32 | end 33 | 34 | public.init = function() 35 | inputQueue = Queue(); 36 | outputQueue = Queue(); 37 | return public; 38 | end 39 | 40 | public.update = function(messageStream) 41 | local byte = messageStream(); 42 | while (byte ~= nil) do 43 | inputQueue.push(byte); 44 | if(inputQueue.size() >= blockCipher.blockSize) then 45 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 46 | 47 | block = blockCipher.encrypt(key, block); 48 | 49 | Array.writeToQueue(outputQueue, block); 50 | end 51 | byte = messageStream(); 52 | end 53 | return public; 54 | end 55 | 56 | public.finish = function() 57 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 58 | public.update(paddingStream); 59 | 60 | return public; 61 | end 62 | 63 | public.getOutputQueue = function() 64 | return outputQueue; 65 | end 66 | 67 | public.asHex = function() 68 | return Stream.toHex(outputQueue.pop); 69 | end 70 | 71 | public.asBytes = function() 72 | return Stream.toArray(outputQueue.pop); 73 | end 74 | 75 | public.asString = function() 76 | return Stream.toString(outputQueue.pop); 77 | end 78 | 79 | return public; 80 | 81 | end 82 | 83 | ECB.Decipher = function() 84 | 85 | local public = {}; 86 | 87 | local key; 88 | local blockCipher; 89 | local padding; 90 | local inputQueue; 91 | local outputQueue; 92 | 93 | public.setKey = function(keyBytes) 94 | key = keyBytes; 95 | return public; 96 | end 97 | 98 | public.setBlockCipher = function(cipher) 99 | blockCipher = cipher; 100 | return public; 101 | end 102 | 103 | public.setPadding = function(paddingMode) 104 | padding = paddingMode; 105 | return public; 106 | end 107 | 108 | public.init = function() 109 | inputQueue = Queue(); 110 | outputQueue = Queue(); 111 | return public; 112 | end 113 | 114 | public.update = function(messageStream) 115 | local byte = messageStream(); 116 | while (byte ~= nil) do 117 | inputQueue.push(byte); 118 | if(inputQueue.size() >= blockCipher.blockSize) then 119 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 120 | 121 | block = blockCipher.decrypt(key, block); 122 | 123 | Array.writeToQueue(outputQueue, block); 124 | end 125 | byte = messageStream(); 126 | end 127 | return public; 128 | end 129 | 130 | public.finish = function() 131 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 132 | public.update(paddingStream); 133 | 134 | return public; 135 | end 136 | 137 | public.getOutputQueue = function() 138 | return outputQueue; 139 | end 140 | 141 | public.asHex = function() 142 | return Stream.toHex(outputQueue.pop); 143 | end 144 | 145 | public.asBytes = function() 146 | return Stream.toArray(outputQueue.pop); 147 | end 148 | 149 | public.asString = function() 150 | return Stream.toString(outputQueue.pop); 151 | end 152 | 153 | return public; 154 | 155 | end 156 | 157 | 158 | return ECB; 159 | -------------------------------------------------------------------------------- /lockbox/cipher/mode/ige.lua: -------------------------------------------------------------------------------- 1 | local Array = require("lockbox.util.array"); 2 | local Stream = require("lockbox.util.stream"); 3 | local Queue = require("lockbox.util.queue"); 4 | 5 | local IGE = {}; 6 | 7 | IGE.Cipher = function() 8 | 9 | local public = {}; 10 | 11 | local key; 12 | local blockCipher; 13 | local padding; 14 | local inputQueue; 15 | local outputQueue; 16 | local xPrev, yPrev; 17 | 18 | public.setKey = function(keyBytes) 19 | key = keyBytes; 20 | return public; 21 | end 22 | 23 | public.setBlockCipher = function(cipher) 24 | blockCipher = cipher; 25 | return public; 26 | end 27 | 28 | public.setPadding = function(paddingMode) 29 | padding = paddingMode; 30 | return public; 31 | end 32 | 33 | public.init = function() 34 | inputQueue = Queue(); 35 | outputQueue = Queue(); 36 | xPrev = nil; 37 | yPrev = nil; 38 | return public; 39 | end 40 | 41 | public.update = function(messageStream) 42 | local byte = messageStream(); 43 | while (byte ~= nil) do 44 | inputQueue.push(byte); 45 | if(inputQueue.size() >= blockCipher.blockSize) then 46 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 47 | 48 | if(yPrev == nil) then 49 | yPrev = block; 50 | elseif(xPrev == nil) then 51 | xPrev = block 52 | else 53 | local out = Array.XOR(yPrev, block); 54 | out = blockCipher.encrypt(key, out); 55 | out = Array.XOR(out, xPrev); 56 | Array.writeToQueue(outputQueue, out); 57 | xPrev = block; 58 | yPrev = out; 59 | end 60 | end 61 | byte = messageStream(); 62 | end 63 | return public; 64 | end 65 | 66 | public.finish = function() 67 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 68 | public.update(paddingStream); 69 | 70 | return public; 71 | end 72 | 73 | public.getOutputQueue = function() 74 | return outputQueue; 75 | end 76 | 77 | public.asHex = function() 78 | return Stream.toHex(outputQueue.pop); 79 | end 80 | 81 | public.asBytes = function() 82 | return Stream.toArray(outputQueue.pop); 83 | end 84 | 85 | public.asString = function() 86 | return Stream.toString(outputQueue.pop); 87 | end 88 | 89 | return public; 90 | 91 | end 92 | 93 | IGE.Decipher = function() 94 | 95 | local public = {}; 96 | 97 | local key; 98 | local blockCipher; 99 | local padding; 100 | local inputQueue; 101 | local outputQueue; 102 | local xPrev, yPrev; 103 | 104 | public.setKey = function(keyBytes) 105 | key = keyBytes; 106 | return public; 107 | end 108 | 109 | public.setBlockCipher = function(cipher) 110 | blockCipher = cipher; 111 | return public; 112 | end 113 | 114 | public.setPadding = function(paddingMode) 115 | padding = paddingMode; 116 | return public; 117 | end 118 | 119 | public.init = function() 120 | inputQueue = Queue(); 121 | outputQueue = Queue(); 122 | xPrev = nil; 123 | yPrev = nil; 124 | return public; 125 | end 126 | 127 | public.update = function(messageStream) 128 | local byte = messageStream(); 129 | while (byte ~= nil) do 130 | inputQueue.push(byte); 131 | if(inputQueue.size() >= blockCipher.blockSize) then 132 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 133 | 134 | if(xPrev == nil) then 135 | xPrev = block; 136 | elseif(yPrev == nil) then 137 | yPrev = block 138 | else 139 | local out = Array.XOR(yPrev, block); 140 | out = blockCipher.decrypt(key, out); 141 | out = Array.XOR(out, xPrev); 142 | Array.writeToQueue(outputQueue, out); 143 | xPrev = block; 144 | yPrev = out; 145 | end 146 | end 147 | byte = messageStream(); 148 | end 149 | return public; 150 | end 151 | 152 | public.finish = function() 153 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 154 | public.update(paddingStream); 155 | 156 | return public; 157 | end 158 | 159 | public.getOutputQueue = function() 160 | return outputQueue; 161 | end 162 | 163 | public.asHex = function() 164 | return Stream.toHex(outputQueue.pop); 165 | end 166 | 167 | public.asBytes = function() 168 | return Stream.toArray(outputQueue.pop); 169 | end 170 | 171 | public.asString = function() 172 | return Stream.toString(outputQueue.pop); 173 | end 174 | 175 | return public; 176 | 177 | end 178 | 179 | return IGE; 180 | 181 | -------------------------------------------------------------------------------- /lockbox/cipher/mode/ofb.lua: -------------------------------------------------------------------------------- 1 | local Array = require("lockbox.util.array"); 2 | local Stream = require("lockbox.util.stream"); 3 | local Queue = require("lockbox.util.queue"); 4 | 5 | local OFB = {}; 6 | 7 | OFB.Cipher = function() 8 | 9 | local public = {}; 10 | 11 | local key; 12 | local blockCipher; 13 | local padding; 14 | local inputQueue; 15 | local outputQueue; 16 | local iv; 17 | 18 | public.setKey = function(keyBytes) 19 | key = keyBytes; 20 | return public; 21 | end 22 | 23 | public.setBlockCipher = function(cipher) 24 | blockCipher = cipher; 25 | return public; 26 | end 27 | 28 | public.setPadding = function(paddingMode) 29 | padding = paddingMode; 30 | return public; 31 | end 32 | 33 | public.init = function() 34 | inputQueue = Queue(); 35 | outputQueue = Queue(); 36 | iv = nil; 37 | return public; 38 | end 39 | 40 | public.update = function(messageStream) 41 | local byte = messageStream(); 42 | while (byte ~= nil) do 43 | inputQueue.push(byte); 44 | if(inputQueue.size() >= blockCipher.blockSize) then 45 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 46 | 47 | if(iv == nil) then 48 | iv = block; 49 | else 50 | local out = iv; 51 | out = blockCipher.encrypt(key, out); 52 | iv = out; 53 | out = Array.XOR(out, block); 54 | Array.writeToQueue(outputQueue, out); 55 | end 56 | end 57 | byte = messageStream(); 58 | end 59 | return public; 60 | end 61 | 62 | public.finish = function() 63 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 64 | public.update(paddingStream); 65 | 66 | return public; 67 | end 68 | 69 | public.getOutputQueue = function() 70 | return outputQueue; 71 | end 72 | 73 | public.asHex = function() 74 | return Stream.toHex(outputQueue.pop); 75 | end 76 | 77 | public.asBytes = function() 78 | return Stream.toArray(outputQueue.pop); 79 | end 80 | 81 | public.asString = function() 82 | return Stream.toString(outputQueue.pop); 83 | end 84 | 85 | return public; 86 | 87 | end 88 | 89 | OFB.Decipher = function() 90 | 91 | local public = {}; 92 | 93 | local key; 94 | local blockCipher; 95 | local padding; 96 | local inputQueue; 97 | local outputQueue; 98 | local iv; 99 | 100 | public.setKey = function(keyBytes) 101 | key = keyBytes; 102 | return public; 103 | end 104 | 105 | public.setBlockCipher = function(cipher) 106 | blockCipher = cipher; 107 | return public; 108 | end 109 | 110 | public.setPadding = function(paddingMode) 111 | padding = paddingMode; 112 | return public; 113 | end 114 | 115 | public.init = function() 116 | inputQueue = Queue(); 117 | outputQueue = Queue(); 118 | iv = nil; 119 | return public; 120 | end 121 | 122 | public.update = function(messageStream) 123 | local byte = messageStream(); 124 | while (byte ~= nil) do 125 | inputQueue.push(byte); 126 | if(inputQueue.size() >= blockCipher.blockSize) then 127 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 128 | 129 | if(iv == nil) then 130 | iv = block; 131 | else 132 | local out = iv; 133 | out = blockCipher.encrypt(key, out); 134 | iv = out; 135 | out = Array.XOR(out, block); 136 | Array.writeToQueue(outputQueue, out); 137 | end 138 | end 139 | byte = messageStream(); 140 | end 141 | return public; 142 | end 143 | 144 | public.finish = function() 145 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 146 | public.update(paddingStream); 147 | 148 | return public; 149 | end 150 | 151 | public.getOutputQueue = function() 152 | return outputQueue; 153 | end 154 | 155 | public.asHex = function() 156 | return Stream.toHex(outputQueue.pop); 157 | end 158 | 159 | public.asBytes = function() 160 | return Stream.toArray(outputQueue.pop); 161 | end 162 | 163 | public.asString = function() 164 | return Stream.toString(outputQueue.pop); 165 | end 166 | 167 | return public; 168 | 169 | end 170 | 171 | 172 | return OFB; 173 | -------------------------------------------------------------------------------- /lockbox/cipher/mode/pcbc.lua: -------------------------------------------------------------------------------- 1 | local Array = require("lockbox.util.array"); 2 | local Stream = require("lockbox.util.stream"); 3 | local Queue = require("lockbox.util.queue"); 4 | 5 | local PCBC = {}; 6 | 7 | PCBC.Cipher = function() 8 | 9 | local public = {}; 10 | 11 | local key; 12 | local blockCipher; 13 | local padding; 14 | local inputQueue; 15 | local outputQueue; 16 | local iv; 17 | 18 | public.setKey = function(keyBytes) 19 | key = keyBytes; 20 | return public; 21 | end 22 | 23 | public.setBlockCipher = function(cipher) 24 | blockCipher = cipher; 25 | return public; 26 | end 27 | 28 | public.setPadding = function(paddingMode) 29 | padding = paddingMode; 30 | return public; 31 | end 32 | 33 | public.init = function() 34 | inputQueue = Queue(); 35 | outputQueue = Queue(); 36 | iv = nil; 37 | return public; 38 | end 39 | 40 | public.update = function(messageStream) 41 | local byte = messageStream(); 42 | while (byte ~= nil) do 43 | inputQueue.push(byte); 44 | if(inputQueue.size() >= blockCipher.blockSize) then 45 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 46 | 47 | if(iv == nil) then 48 | iv = block; 49 | else 50 | local out = block; 51 | out = Array.XOR(iv, out); 52 | out = blockCipher.encrypt(key, out); 53 | iv = Array.XOR(out, block); 54 | Array.writeToQueue(outputQueue, out); 55 | end 56 | end 57 | byte = messageStream(); 58 | end 59 | return public; 60 | end 61 | 62 | public.finish = function() 63 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 64 | public.update(paddingStream); 65 | 66 | return public; 67 | end 68 | 69 | public.getOutputQueue = function() 70 | return outputQueue; 71 | end 72 | 73 | public.asHex = function() 74 | return Stream.toHex(outputQueue.pop); 75 | end 76 | 77 | public.asBytes = function() 78 | return Stream.toArray(outputQueue.pop); 79 | end 80 | 81 | public.asString = function() 82 | return Stream.toString(outputQueue.pop); 83 | end 84 | 85 | return public; 86 | 87 | end 88 | 89 | PCBC.Decipher = function() 90 | 91 | local public = {}; 92 | 93 | local key; 94 | local blockCipher; 95 | local padding; 96 | local inputQueue; 97 | local outputQueue; 98 | local iv; 99 | 100 | public.setKey = function(keyBytes) 101 | key = keyBytes; 102 | return public; 103 | end 104 | 105 | public.setBlockCipher = function(cipher) 106 | blockCipher = cipher; 107 | return public; 108 | end 109 | 110 | public.setPadding = function(paddingMode) 111 | padding = paddingMode; 112 | return public; 113 | end 114 | 115 | public.init = function() 116 | inputQueue = Queue(); 117 | outputQueue = Queue(); 118 | iv = nil; 119 | return public; 120 | end 121 | 122 | public.update = function(messageStream) 123 | local byte = messageStream(); 124 | while (byte ~= nil) do 125 | inputQueue.push(byte); 126 | if(inputQueue.size() >= blockCipher.blockSize) then 127 | local block = Array.readFromQueue(inputQueue, blockCipher.blockSize); 128 | 129 | if(iv == nil) then 130 | iv = block; 131 | else 132 | local out = block; 133 | out = blockCipher.decrypt(key, out); 134 | out = Array.XOR(iv, out); 135 | Array.writeToQueue(outputQueue, out); 136 | iv = Array.XOR(out, block); 137 | end 138 | end 139 | byte = messageStream(); 140 | end 141 | return public; 142 | end 143 | 144 | public.finish = function() 145 | local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead()); 146 | public.update(paddingStream); 147 | 148 | return public; 149 | end 150 | 151 | public.getOutputQueue = function() 152 | return outputQueue; 153 | end 154 | 155 | public.asHex = function() 156 | return Stream.toHex(outputQueue.pop); 157 | end 158 | 159 | public.asBytes = function() 160 | return Stream.toArray(outputQueue.pop); 161 | end 162 | 163 | public.asString = function() 164 | return Stream.toString(outputQueue.pop); 165 | end 166 | 167 | return public; 168 | 169 | end 170 | 171 | 172 | return PCBC; 173 | -------------------------------------------------------------------------------- /lockbox/cipher/tea.lua: -------------------------------------------------------------------------------- 1 | require("lockbox").insecure(); 2 | 3 | local Bit = require("lockbox.util.bit"); 4 | 5 | local AND = Bit.band; 6 | local OR = Bit.bor; 7 | local XOR = Bit.bxor; 8 | local LSHIFT = Bit.lshift; 9 | local RSHIFT = Bit.rshift; 10 | 11 | 12 | --NOTE: TEA is endian-dependent! 13 | --The spec does not seem to specify which to use. 14 | --It looks like most implementations use big-endian 15 | local bytes2word = function(b0, b1, b2, b3) 16 | local i = b0; i = LSHIFT(i, 8); 17 | i = OR(i, b1); i = LSHIFT(i, 8); 18 | i = OR(i, b2); i = LSHIFT(i, 8); 19 | i = OR(i, b3); 20 | return i; 21 | end 22 | 23 | local word2bytes = function(word) 24 | local b0, b1, b2, b3; 25 | b3 = AND(word, 0xFF); word = RSHIFT(word, 8); 26 | b2 = AND(word, 0xFF); word = RSHIFT(word, 8); 27 | b1 = AND(word, 0xFF); word = RSHIFT(word, 8); 28 | b0 = AND(word, 0xFF); 29 | return b0, b1, b2, b3; 30 | end 31 | 32 | local TEA = {}; 33 | 34 | TEA.blockSize = 8; 35 | 36 | TEA.encrypt = function(key, data) 37 | local y = bytes2word(data[1], data[2], data[3], data[4]); 38 | local z = bytes2word(data[5], data[6], data[7], data[8]); 39 | local delta = 0x9e3779b9; 40 | local sum = 0; 41 | 42 | local k0 = bytes2word(key[ 1], key[ 2], key[ 3], key[ 4]); 43 | local k1 = bytes2word(key[ 5], key[ 6], key[ 7], key[ 8]); 44 | local k2 = bytes2word(key[ 9], key[10], key[11], key[12]); 45 | local k3 = bytes2word(key[13], key[14], key[15], key[16]); 46 | 47 | for _ = 1, 32 do 48 | local temp; 49 | 50 | sum = AND(sum + delta, 0xFFFFFFFF); 51 | 52 | temp = z + sum; 53 | temp = XOR(temp, LSHIFT(z, 4) + k0); 54 | temp = XOR(temp, RSHIFT(z, 5) + k1); 55 | y = AND(y + temp, 0xFFFFFFFF); 56 | 57 | temp = y + sum; 58 | temp = XOR(temp, LSHIFT(y, 4) + k2); 59 | temp = XOR(temp, RSHIFT(y, 5) + k3); 60 | z = AND( z + temp, 0xFFFFFFFF); 61 | end 62 | 63 | local out = {}; 64 | 65 | out[1], out[2], out[3], out[4] = word2bytes(y); 66 | out[5], out[6], out[7], out[8] = word2bytes(z); 67 | 68 | return out; 69 | end 70 | 71 | TEA.decrypt = function(key, data) 72 | local y = bytes2word(data[1], data[2], data[3], data[4]); 73 | local z = bytes2word(data[5], data[6], data[7], data[8]); 74 | 75 | local delta = 0x9e3779b9; 76 | local sum = 0xc6ef3720; --AND(delta*32,0xFFFFFFFF); 77 | 78 | local k0 = bytes2word(key[ 1], key[ 2], key[ 3], key[ 4]); 79 | local k1 = bytes2word(key[ 5], key[ 6], key[ 7], key[ 8]); 80 | local k2 = bytes2word(key[ 9], key[10], key[11], key[12]); 81 | local k3 = bytes2word(key[13], key[14], key[15], key[16]); 82 | 83 | for _ = 1, 32 do 84 | local temp; 85 | 86 | temp = y + sum; 87 | temp = XOR(temp, LSHIFT(y, 4) + k2); 88 | temp = XOR(temp, RSHIFT(y, 5) + k3); 89 | z = AND(z + 0x100000000 - temp, 0xFFFFFFFF); 90 | 91 | temp = z + sum; 92 | temp = XOR(temp, LSHIFT(z, 4) + k0); 93 | temp = XOR(temp, RSHIFT(z, 5) + k1); 94 | y = AND(y + 0x100000000 - temp, 0xFFFFFFFF); 95 | 96 | sum = AND(sum + 0x100000000 - delta, 0xFFFFFFFF); 97 | end 98 | 99 | local out = {}; 100 | 101 | out[1], out[2], out[3], out[4] = word2bytes(y); 102 | out[5], out[6], out[7], out[8] = word2bytes(z); 103 | 104 | return out; 105 | end 106 | 107 | return TEA; 108 | -------------------------------------------------------------------------------- /lockbox/cipher/xtea.lua: -------------------------------------------------------------------------------- 1 | require("lockbox").insecure(); 2 | 3 | local Bit = require("lockbox.util.bit"); 4 | 5 | local AND = Bit.band; 6 | local OR = Bit.bor; 7 | local XOR = Bit.bxor; 8 | local LSHIFT = Bit.lshift; 9 | local RSHIFT = Bit.rshift; 10 | 11 | 12 | --NOTE: XTEA is endian-dependent! 13 | --The spec does not seem to specify which to use. 14 | --It looks like most implementations use big-endian 15 | local bytes2word = function(b0, b1, b2, b3) 16 | local i = b0; i = LSHIFT(i, 8); 17 | i = OR(i, b1); i = LSHIFT(i, 8); 18 | i = OR(i, b2); i = LSHIFT(i, 8); 19 | i = OR(i, b3); 20 | return i; 21 | end 22 | 23 | local word2bytes = function(word) 24 | local b0, b1, b2, b3; 25 | b3 = AND(word, 0xFF); word = RSHIFT(word, 8); 26 | b2 = AND(word, 0xFF); word = RSHIFT(word, 8); 27 | b1 = AND(word, 0xFF); word = RSHIFT(word, 8); 28 | b0 = AND(word, 0xFF); 29 | return b0, b1, b2, b3; 30 | end 31 | 32 | local XTEA = {}; 33 | 34 | XTEA.blockSize = 8; 35 | 36 | XTEA.encrypt = function(key, data) 37 | local y = bytes2word(data[1], data[2], data[3], data[4]); 38 | local z = bytes2word(data[5], data[6], data[7], data[8]); 39 | local delta = 0x9e3779b9; 40 | local sum = 0; 41 | 42 | local k0 = bytes2word(key[ 1], key[ 2], key[ 3], key[ 4]); 43 | local k1 = bytes2word(key[ 5], key[ 6], key[ 7], key[ 8]); 44 | local k2 = bytes2word(key[ 9], key[10], key[11], key[12]); 45 | local k3 = bytes2word(key[13], key[14], key[15], key[16]); 46 | local k = {[0] = k0, k1, k2, k3}; 47 | 48 | for _ = 1, 32 do 49 | local temp; 50 | 51 | temp = XOR(LSHIFT(z, 4), RSHIFT(z, 5)) + z 52 | temp = XOR(temp, sum + k[ AND(sum, 0x3) ]) 53 | y = AND(y + temp, 0xFFFFFFFF); 54 | 55 | sum = AND(sum + delta, 0xFFFFFFFF); 56 | 57 | temp = XOR(LSHIFT(y, 4), RSHIFT(y, 5)) + y 58 | temp = XOR(temp, sum + k[ AND(RSHIFT(sum, 11), 0x3) ]) 59 | z = AND( z + temp, 0xFFFFFFFF); 60 | end 61 | 62 | local out = {}; 63 | 64 | out[1], out[2], out[3], out[4] = word2bytes(y); 65 | out[5], out[6], out[7], out[8] = word2bytes(z); 66 | 67 | return out; 68 | end 69 | 70 | XTEA.decrypt = function(key, data) 71 | local y = bytes2word(data[1], data[2], data[3], data[4]); 72 | local z = bytes2word(data[5], data[6], data[7], data[8]); 73 | 74 | local delta = 0x9e3779b9; 75 | local sum = 0xc6ef3720; --AND(delta*32,0xFFFFFFFF); 76 | 77 | local k0 = bytes2word(key[ 1], key[ 2], key[ 3], key[ 4]); 78 | local k1 = bytes2word(key[ 5], key[ 6], key[ 7], key[ 8]); 79 | local k2 = bytes2word(key[ 9], key[10], key[11], key[12]); 80 | local k3 = bytes2word(key[13], key[14], key[15], key[16]); 81 | local k = {[0] = k0, k1, k2, k3}; 82 | 83 | for _ = 1, 32 do 84 | local temp; 85 | 86 | temp = XOR(LSHIFT(y, 4), RSHIFT(y, 5)) + y 87 | temp = XOR(temp, sum + k[ AND(RSHIFT(sum, 11), 0x3) ]) 88 | z = AND(z + 0x100000000 - temp, 0xFFFFFFFF); 89 | 90 | sum = AND(sum + 0x100000000 - delta, 0xFFFFFFFF); 91 | 92 | temp = XOR(LSHIFT(z, 4), RSHIFT(z, 5)) + z 93 | temp = XOR(temp, sum + k[ AND(sum, 0x3) ]) 94 | y = AND(y + 0x100000000 - temp, 0xFFFFFFFF); 95 | 96 | end 97 | 98 | local out = {}; 99 | 100 | out[1], out[2], out[3], out[4] = word2bytes(y); 101 | out[5], out[6], out[7], out[8] = word2bytes(z); 102 | 103 | return out; 104 | end 105 | 106 | return XTEA; 107 | -------------------------------------------------------------------------------- /lockbox/digest/md2.lua: -------------------------------------------------------------------------------- 1 | require("lockbox").insecure(); 2 | 3 | local Bit = require("lockbox.util.bit"); 4 | local String = require("string"); 5 | local Queue = require("lockbox.util.queue"); 6 | 7 | local SUBST = { 8 | 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 9 | 0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA, 10 | 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 11 | 0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A, 12 | 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, 13 | 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 14 | 0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6, 15 | 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 16 | 0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02, 17 | 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, 18 | 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 19 | 0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52, 20 | 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 21 | 0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39, 22 | 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, 23 | 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14 }; 24 | 25 | local XOR = Bit.bxor; 26 | 27 | local MD2 = function() 28 | 29 | local queue = Queue(); 30 | 31 | local X = {}; 32 | for i = 0, 47 do 33 | X[i] = 0x00; 34 | end 35 | 36 | local C = {}; 37 | for i = 0, 15 do 38 | C[i] = 0x00; 39 | end 40 | 41 | local public = {}; 42 | 43 | local processBlock = function() 44 | local block = {}; 45 | 46 | for i = 0, 15 do 47 | block[i] = queue.pop(); 48 | end 49 | 50 | for i = 0, 15 do 51 | X[i + 16] = block[i]; 52 | X[i + 32] = XOR(X[i], block[i]); --mix 53 | end 54 | 55 | local t; 56 | 57 | --update block 58 | t = 0; 59 | for i = 0, 17 do 60 | for j = 0, 47 do 61 | X[j] = XOR(X[j], SUBST[t + 1]); 62 | t = X[j]; 63 | end 64 | t = (t + i) % 256; 65 | end 66 | 67 | --update checksum 68 | t = C[15]; 69 | for i = 0, 15 do 70 | C[i] = XOR(C[i], SUBST[XOR(block[i], t) + 1]); 71 | t = C[i]; 72 | end 73 | 74 | end 75 | 76 | public.init = function() 77 | queue.reset(); 78 | 79 | X = {}; 80 | for i = 0, 47 do 81 | X[i] = 0x00; 82 | end 83 | 84 | C = {}; 85 | for i = 0, 15 do 86 | C[i] = 0x00; 87 | end 88 | 89 | return public; 90 | end 91 | 92 | public.update = function(stream) 93 | for b in stream do 94 | queue.push(b); 95 | if(queue.size() >= 16) then processBlock(); end 96 | end 97 | 98 | return public; 99 | end 100 | 101 | public.finish = function() 102 | local i = 16 - queue.size(); 103 | 104 | while queue.size() < 16 do 105 | queue.push(i); 106 | end 107 | 108 | processBlock(); 109 | 110 | queue.push(C[ 0]); queue.push(C[ 1]); queue.push(C[ 2]); queue.push(C[ 3]); 111 | queue.push(C[ 4]); queue.push(C[ 5]); queue.push(C[ 6]); queue.push(C[ 7]); 112 | queue.push(C[ 8]); queue.push(C[ 9]); queue.push(C[10]); queue.push(C[11]); 113 | queue.push(C[12]); queue.push(C[13]); queue.push(C[14]); queue.push(C[15]); 114 | 115 | processBlock(); 116 | 117 | return public; 118 | end 119 | 120 | public.asBytes = function() 121 | return {X[ 0], X[ 1], X[ 2], X[ 3], X[ 4], X[ 5], X[ 6], X[ 7], 122 | X[ 8], X[ 9], X[10], X[11], X[12], X[13], X[14], X[15]}; 123 | end 124 | 125 | public.asHex = function() 126 | return String.format("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 127 | X[ 0], X[ 1], X[ 2], X[ 3], X[ 4], X[ 5], X[ 6], X[ 7], 128 | X[ 8], X[ 9], X[10], X[11], X[12], X[13], X[14], X[15]); 129 | end 130 | 131 | public.asString = function() 132 | return string.pack(string.rep('B', 16), 133 | X[ 0], X[ 1], X[ 2], X[ 3], X[ 4], X[ 5], X[ 6], X[ 7], 134 | X[ 8], X[ 9], X[10], X[11], X[12], X[13], X[14], X[15]); 135 | end 136 | 137 | return public; 138 | 139 | end 140 | 141 | return MD2; 142 | -------------------------------------------------------------------------------- /lockbox/digest/md4.lua: -------------------------------------------------------------------------------- 1 | require("lockbox").insecure(); 2 | 3 | local Bit = require("lockbox.util.bit"); 4 | local String = require("string"); 5 | local Math = require("math"); 6 | local Queue = require("lockbox.util.queue"); 7 | 8 | local AND = Bit.band; 9 | local OR = Bit.bor; 10 | local NOT = Bit.bnot; 11 | local XOR = Bit.bxor; 12 | local LROT = Bit.lrotate; 13 | local LSHIFT = Bit.lshift; 14 | local RSHIFT = Bit.rshift; 15 | 16 | --MD4 is little-endian 17 | local bytes2word = function(b0, b1, b2, b3) 18 | local i = b3; i = LSHIFT(i, 8); 19 | i = OR(i, b2); i = LSHIFT(i, 8); 20 | i = OR(i, b1); i = LSHIFT(i, 8); 21 | i = OR(i, b0); 22 | return i; 23 | end 24 | 25 | local word2bytes = function(word) 26 | local b0, b1, b2, b3; 27 | b0 = AND(word, 0xFF); word = RSHIFT(word, 8); 28 | b1 = AND(word, 0xFF); word = RSHIFT(word, 8); 29 | b2 = AND(word, 0xFF); word = RSHIFT(word, 8); 30 | b3 = AND(word, 0xFF); 31 | return b0, b1, b2, b3; 32 | end 33 | 34 | local dword2bytes = function(i) 35 | local b4, b5, b6, b7 = word2bytes(Math.floor(i / 0x100000000)); 36 | local b0, b1, b2, b3 = word2bytes(i); 37 | return b0, b1, b2, b3, b4, b5, b6, b7; 38 | end 39 | 40 | local F = function(x, y, z) return OR(AND(x, y), AND(NOT(x), z)); end 41 | local G = function(x, y, z) return OR(AND(x, y), OR(AND(x, z), AND(y, z))); end 42 | local H = function(x, y, z) return XOR(x, XOR(y, z)); end 43 | 44 | 45 | local MD4 = function() 46 | 47 | local queue = Queue(); 48 | 49 | local A = 0x67452301; 50 | local B = 0xefcdab89; 51 | local C = 0x98badcfe; 52 | local D = 0x10325476; 53 | local public = {}; 54 | 55 | local processBlock = function() 56 | local a = A; 57 | local b = B; 58 | local c = C; 59 | local d = D; 60 | 61 | local X = {}; 62 | 63 | for i = 0, 15 do 64 | X[i] = bytes2word(queue.pop(), queue.pop(), queue.pop(), queue.pop()); 65 | end 66 | 67 | a = LROT(a + F(b, c, d) + X[ 0], 3); 68 | d = LROT(d + F(a, b, c) + X[ 1], 7); 69 | c = LROT(c + F(d, a, b) + X[ 2], 11); 70 | b = LROT(b + F(c, d, a) + X[ 3], 19); 71 | 72 | a = LROT(a + F(b, c, d) + X[ 4], 3); 73 | d = LROT(d + F(a, b, c) + X[ 5], 7); 74 | c = LROT(c + F(d, a, b) + X[ 6], 11); 75 | b = LROT(b + F(c, d, a) + X[ 7], 19); 76 | 77 | a = LROT(a + F(b, c, d) + X[ 8], 3); 78 | d = LROT(d + F(a, b, c) + X[ 9], 7); 79 | c = LROT(c + F(d, a, b) + X[10], 11); 80 | b = LROT(b + F(c, d, a) + X[11], 19); 81 | 82 | a = LROT(a + F(b, c, d) + X[12], 3); 83 | d = LROT(d + F(a, b, c) + X[13], 7); 84 | c = LROT(c + F(d, a, b) + X[14], 11); 85 | b = LROT(b + F(c, d, a) + X[15], 19); 86 | 87 | 88 | a = LROT(a + G(b, c, d) + X[ 0] + 0x5A827999, 3); 89 | d = LROT(d + G(a, b, c) + X[ 4] + 0x5A827999, 5); 90 | c = LROT(c + G(d, a, b) + X[ 8] + 0x5A827999, 9); 91 | b = LROT(b + G(c, d, a) + X[12] + 0x5A827999, 13); 92 | 93 | a = LROT(a + G(b, c, d) + X[ 1] + 0x5A827999, 3); 94 | d = LROT(d + G(a, b, c) + X[ 5] + 0x5A827999, 5); 95 | c = LROT(c + G(d, a, b) + X[ 9] + 0x5A827999, 9); 96 | b = LROT(b + G(c, d, a) + X[13] + 0x5A827999, 13); 97 | 98 | a = LROT(a + G(b, c, d) + X[ 2] + 0x5A827999, 3); 99 | d = LROT(d + G(a, b, c) + X[ 6] + 0x5A827999, 5); 100 | c = LROT(c + G(d, a, b) + X[10] + 0x5A827999, 9); 101 | b = LROT(b + G(c, d, a) + X[14] + 0x5A827999, 13); 102 | 103 | a = LROT(a + G(b, c, d) + X[ 3] + 0x5A827999, 3); 104 | d = LROT(d + G(a, b, c) + X[ 7] + 0x5A827999, 5); 105 | c = LROT(c + G(d, a, b) + X[11] + 0x5A827999, 9); 106 | b = LROT(b + G(c, d, a) + X[15] + 0x5A827999, 13); 107 | 108 | 109 | a = LROT(a + H(b, c, d) + X[ 0] + 0x6ED9EBA1, 3); 110 | d = LROT(d + H(a, b, c) + X[ 8] + 0x6ED9EBA1, 9); 111 | c = LROT(c + H(d, a, b) + X[ 4] + 0x6ED9EBA1, 11); 112 | b = LROT(b + H(c, d, a) + X[12] + 0x6ED9EBA1, 15); 113 | 114 | a = LROT(a + H(b, c, d) + X[ 2] + 0x6ED9EBA1, 3); 115 | d = LROT(d + H(a, b, c) + X[10] + 0x6ED9EBA1, 9); 116 | c = LROT(c + H(d, a, b) + X[ 6] + 0x6ED9EBA1, 11); 117 | b = LROT(b + H(c, d, a) + X[14] + 0x6ED9EBA1, 15); 118 | 119 | a = LROT(a + H(b, c, d) + X[ 1] + 0x6ED9EBA1, 3); 120 | d = LROT(d + H(a, b, c) + X[ 9] + 0x6ED9EBA1, 9); 121 | c = LROT(c + H(d, a, b) + X[ 5] + 0x6ED9EBA1, 11); 122 | b = LROT(b + H(c, d, a) + X[13] + 0x6ED9EBA1, 15); 123 | 124 | a = LROT(a + H(b, c, d) + X[ 3] + 0x6ED9EBA1, 3); 125 | d = LROT(d + H(a, b, c) + X[11] + 0x6ED9EBA1, 9); 126 | c = LROT(c + H(d, a, b) + X[ 7] + 0x6ED9EBA1, 11); 127 | b = LROT(b + H(c, d, a) + X[15] + 0x6ED9EBA1, 15); 128 | 129 | 130 | A = AND(A + a, 0xFFFFFFFF); 131 | B = AND(B + b, 0xFFFFFFFF); 132 | C = AND(C + c, 0xFFFFFFFF); 133 | D = AND(D + d, 0xFFFFFFFF); 134 | end 135 | 136 | public.init = function() 137 | queue.reset(); 138 | 139 | A = 0x67452301; 140 | B = 0xefcdab89; 141 | C = 0x98badcfe; 142 | D = 0x10325476; 143 | 144 | return public; 145 | end 146 | 147 | public.update = function(bytes) 148 | for b in bytes do 149 | queue.push(b); 150 | if(queue.size() >= 64) then processBlock(); end 151 | end 152 | 153 | return public; 154 | end 155 | 156 | public.finish = function() 157 | local bits = queue.getHead() * 8; 158 | 159 | queue.push(0x80); 160 | while ((queue.size() + 7) % 64) < 63 do 161 | queue.push(0x00); 162 | end 163 | 164 | local b0, b1, b2, b3, b4, b5, b6, b7 = dword2bytes(bits); 165 | 166 | queue.push(b0); 167 | queue.push(b1); 168 | queue.push(b2); 169 | queue.push(b3); 170 | queue.push(b4); 171 | queue.push(b5); 172 | queue.push(b6); 173 | queue.push(b7); 174 | 175 | while queue.size() > 0 do 176 | processBlock(); 177 | end 178 | 179 | return public; 180 | end 181 | 182 | public.asBytes = function() 183 | local b0, b1, b2, b3 = word2bytes(A); 184 | local b4, b5, b6, b7 = word2bytes(B); 185 | local b8, b9, b10, b11 = word2bytes(C); 186 | local b12, b13, b14, b15 = word2bytes(D); 187 | 188 | return {b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15}; 189 | end 190 | 191 | public.asHex = function() 192 | local b0, b1, b2, b3 = word2bytes(A); 193 | local b4, b5, b6, b7 = word2bytes(B); 194 | local b8, b9, b10, b11 = word2bytes(C); 195 | local b12, b13, b14, b15 = word2bytes(D); 196 | 197 | return String.format("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 198 | b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15); 199 | end 200 | 201 | public.asString = function() 202 | local b0, b1, b2, b3 = word2bytes(A); 203 | local b4, b5, b6, b7 = word2bytes(B); 204 | local b8, b9, b10, b11 = word2bytes(C); 205 | local b12, b13, b14, b15 = word2bytes(D); 206 | 207 | return string.pack(string.rep('B', 16), 208 | b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15); 209 | end 210 | 211 | return public; 212 | 213 | end 214 | 215 | return MD4; 216 | -------------------------------------------------------------------------------- /lockbox/digest/md5.lua: -------------------------------------------------------------------------------- 1 | require("lockbox").insecure(); 2 | 3 | local Bit = require("lockbox.util.bit"); 4 | local String = require("string"); 5 | local Math = require("math"); 6 | local Queue = require("lockbox.util.queue"); 7 | 8 | local SHIFT = { 9 | 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 10 | 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 11 | 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 12 | 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; 13 | 14 | local CONSTANTS = { 15 | 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 16 | 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 17 | 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 18 | 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 19 | 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 20 | 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 21 | 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 22 | 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 23 | 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 24 | 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 25 | 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 26 | 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 27 | 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 28 | 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 29 | 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 30 | 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; 31 | 32 | local AND = Bit.band; 33 | local OR = Bit.bor; 34 | local NOT = Bit.bnot; 35 | local XOR = Bit.bxor; 36 | local LROT = Bit.lrotate; 37 | local LSHIFT = Bit.lshift; 38 | local RSHIFT = Bit.rshift; 39 | 40 | --MD5 is little-endian 41 | local bytes2word = function(b0, b1, b2, b3) 42 | local i = b3; i = LSHIFT(i, 8); 43 | i = OR(i, b2); i = LSHIFT(i, 8); 44 | i = OR(i, b1); i = LSHIFT(i, 8); 45 | i = OR(i, b0); 46 | return i; 47 | end 48 | 49 | local word2bytes = function(word) 50 | local b0, b1, b2, b3; 51 | b0 = AND(word, 0xFF); word = RSHIFT(word, 8); 52 | b1 = AND(word, 0xFF); word = RSHIFT(word, 8); 53 | b2 = AND(word, 0xFF); word = RSHIFT(word, 8); 54 | b3 = AND(word, 0xFF); 55 | return b0, b1, b2, b3; 56 | end 57 | 58 | local dword2bytes = function(i) 59 | local b4, b5, b6, b7 = word2bytes(Math.floor(i / 0x100000000)); 60 | local b0, b1, b2, b3 = word2bytes(i); 61 | return b0, b1, b2, b3, b4, b5, b6, b7; 62 | end 63 | 64 | local F = function(x, y, z) return OR(AND(x, y), AND(NOT(x), z)); end 65 | local G = function(x, y, z) return OR(AND(x, z), AND(y, NOT(z))); end 66 | local H = function(x, y, z) return XOR(x, XOR(y, z)); end 67 | local I = function(x, y, z) return XOR(y, OR(x, NOT(z))); end 68 | 69 | local MD5 = function() 70 | 71 | local queue = Queue(); 72 | 73 | local A = 0x67452301; 74 | local B = 0xefcdab89; 75 | local C = 0x98badcfe; 76 | local D = 0x10325476; 77 | local public = {}; 78 | 79 | local processBlock = function() 80 | local a = A; 81 | local b = B; 82 | local c = C; 83 | local d = D; 84 | 85 | local X = {}; 86 | 87 | for i = 1, 16 do 88 | X[i] = bytes2word(queue.pop(), queue.pop(), queue.pop(), queue.pop()); 89 | end 90 | 91 | for i = 0, 63 do 92 | local f, g, temp; 93 | 94 | if (0 <= i) and (i <= 15) then 95 | f = F(b, c, d); 96 | g = i; 97 | elseif (16 <= i) and (i <= 31) then 98 | f = G(b, c, d); 99 | g = (5 * i + 1) % 16; 100 | elseif (32 <= i) and (i <= 47) then 101 | f = H(b, c, d); 102 | g = (3 * i + 5) % 16; 103 | elseif (48 <= i) and (i <= 63) then 104 | f = I(b, c, d); 105 | g = (7 * i) % 16; 106 | end 107 | temp = d; 108 | d = c; 109 | c = b; 110 | b = b + LROT((a + f + CONSTANTS[i + 1] + X[g + 1]), SHIFT[i + 1]); 111 | a = temp; 112 | end 113 | 114 | A = AND(A + a, 0xFFFFFFFF); 115 | B = AND(B + b, 0xFFFFFFFF); 116 | C = AND(C + c, 0xFFFFFFFF); 117 | D = AND(D + d, 0xFFFFFFFF); 118 | end 119 | 120 | public.init = function() 121 | queue.reset(); 122 | 123 | A = 0x67452301; 124 | B = 0xefcdab89; 125 | C = 0x98badcfe; 126 | D = 0x10325476; 127 | 128 | return public; 129 | end 130 | 131 | public.update = function(bytes) 132 | for b in bytes do 133 | queue.push(b); 134 | if(queue.size() >= 64) then processBlock(); end 135 | end 136 | 137 | return public; 138 | end 139 | 140 | public.finish = function() 141 | local bits = queue.getHead() * 8; 142 | 143 | queue.push(0x80); 144 | while ((queue.size() + 7) % 64) < 63 do 145 | queue.push(0x00); 146 | end 147 | 148 | local b0, b1, b2, b3, b4, b5, b6, b7 = dword2bytes(bits); 149 | 150 | queue.push(b0); 151 | queue.push(b1); 152 | queue.push(b2); 153 | queue.push(b3); 154 | queue.push(b4); 155 | queue.push(b5); 156 | queue.push(b6); 157 | queue.push(b7); 158 | 159 | while queue.size() > 0 do 160 | processBlock(); 161 | end 162 | 163 | return public; 164 | end 165 | 166 | public.asBytes = function() 167 | local b0, b1, b2, b3 = word2bytes(A); 168 | local b4, b5, b6, b7 = word2bytes(B); 169 | local b8, b9, b10, b11 = word2bytes(C); 170 | local b12, b13, b14, b15 = word2bytes(D); 171 | 172 | return {b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15}; 173 | end 174 | 175 | public.asHex = function() 176 | local b0, b1, b2, b3 = word2bytes(A); 177 | local b4, b5, b6, b7 = word2bytes(B); 178 | local b8, b9, b10, b11 = word2bytes(C); 179 | local b12, b13, b14, b15 = word2bytes(D); 180 | 181 | return String.format("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 182 | b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15); 183 | end 184 | 185 | public.asString = function() 186 | local b0, b1, b2, b3 = word2bytes(A); 187 | local b4, b5, b6, b7 = word2bytes(B); 188 | local b8, b9, b10, b11 = word2bytes(C); 189 | local b12, b13, b14, b15 = word2bytes(D); 190 | 191 | return string.pack(string.rep('B', 16), 192 | b0, b1, b2, b3, b4, b5, b6, b7, b8, 193 | b9, b10, b11, b12, b13, b14, b15 194 | ) 195 | end 196 | 197 | return public; 198 | 199 | end 200 | 201 | return MD5; 202 | -------------------------------------------------------------------------------- /lockbox/digest/ripemd128.lua: -------------------------------------------------------------------------------- 1 | require("lockbox").insecure(); 2 | 3 | local Bit = require("lockbox.util.bit"); 4 | local String = require("string"); 5 | local Math = require("math"); 6 | local Queue = require("lockbox.util.queue"); 7 | 8 | local AND = Bit.band; 9 | local OR = Bit.bor; 10 | local NOT = Bit.bnot; 11 | local XOR = Bit.bxor; 12 | local LROT = Bit.lrotate; 13 | local LSHIFT = Bit.lshift; 14 | local RSHIFT = Bit.rshift; 15 | 16 | --RIPEMD128 is little-endian 17 | local bytes2word = function(b0, b1, b2, b3) 18 | local i = b3; i = LSHIFT(i, 8); 19 | i = OR(i, b2); i = LSHIFT(i, 8); 20 | i = OR(i, b1); i = LSHIFT(i, 8); 21 | i = OR(i, b0); 22 | return i; 23 | end 24 | 25 | local word2bytes = function(word) 26 | local b0, b1, b2, b3; 27 | b0 = AND(word, 0xFF); word = RSHIFT(word, 8); 28 | b1 = AND(word, 0xFF); word = RSHIFT(word, 8); 29 | b2 = AND(word, 0xFF); word = RSHIFT(word, 8); 30 | b3 = AND(word, 0xFF); 31 | return b0, b1, b2, b3; 32 | end 33 | 34 | local dword2bytes = function(i) 35 | local b4, b5, b6, b7 = word2bytes(Math.floor(i / 0x100000000)); 36 | local b0, b1, b2, b3 = word2bytes(i); 37 | return b0, b1, b2, b3, b4, b5, b6, b7; 38 | end 39 | 40 | local F = function(x, y, z) return XOR(x, XOR(y, z)); end 41 | local G = function(x, y, z) return OR(AND(x, y), AND(NOT(x), z)); end 42 | local H = function(x, y, z) return XOR(OR(x, NOT(y)), z); end 43 | local I = function(x, y, z) return OR(AND(x, z), AND(y, NOT(z))); end 44 | 45 | local FF = function(a, b, c, d, x, s) 46 | a = a + F(b, c, d) + x; 47 | a = LROT(a, s); 48 | a = AND(a, 0xFFFFFFFF); 49 | return a; 50 | end 51 | 52 | local GG = function(a, b, c, d, x, s) 53 | a = a + G(b, c, d) + x + 0x5a827999; 54 | a = LROT(a, s); 55 | a = AND(a, 0xFFFFFFFF); 56 | return a; 57 | end 58 | 59 | local HH = function(a, b, c, d, x, s) 60 | a = a + H(b, c, d) + x + 0x6ed9eba1; 61 | a = LROT(a, s); 62 | a = AND(a, 0xFFFFFFFF); 63 | return a; 64 | end 65 | 66 | local II = function(a, b, c, d, x, s) 67 | a = a + I(b, c, d) + x + 0x8f1bbcdc; 68 | a = LROT(a, s); 69 | a = AND(a, 0xFFFFFFFF); 70 | return a; 71 | end 72 | 73 | 74 | local FFF = function(a, b, c, d, x, s) 75 | a = a + F(b, c, d) + x; 76 | a = LROT(a, s); 77 | a = AND(a, 0xFFFFFFFF); 78 | return a; 79 | end 80 | 81 | local GGG = function(a, b, c, d, x, s) 82 | a = a + G(b, c, d) + x + 0x6d703ef3; 83 | a = LROT(a, s); 84 | a = AND(a, 0xFFFFFFFF); 85 | return a; 86 | end 87 | 88 | local HHH = function(a, b, c, d, x, s) 89 | a = a + H(b, c, d) + x + 0x5c4dd124; 90 | a = LROT(a, s); 91 | a = AND(a, 0xFFFFFFFF); 92 | return a; 93 | end 94 | 95 | local III = function(a, b, c, d, x, s) 96 | a = a + I(b, c, d) + x + 0x50a28be6; 97 | a = LROT(a, s); 98 | a = AND(a, 0xFFFFFFFF); 99 | return a; 100 | end 101 | 102 | local RIPEMD128 = function() 103 | 104 | local queue = Queue(); 105 | 106 | local A = 0x67452301; 107 | local B = 0xefcdab89; 108 | local C = 0x98badcfe; 109 | local D = 0x10325476; 110 | 111 | local public = {}; 112 | 113 | local processBlock = function() 114 | local aa, bb, cc, dd = A, B, C, D; 115 | local aaa, bbb, ccc, ddd = A, B, C, D; 116 | 117 | local X = {}; 118 | 119 | for i = 0, 15 do 120 | X[i] = bytes2word(queue.pop(), queue.pop(), queue.pop(), queue.pop()); 121 | end 122 | 123 | aa = FF(aa, bb, cc, dd, X[ 0], 11); 124 | dd = FF(dd, aa, bb, cc, X[ 1], 14); 125 | cc = FF(cc, dd, aa, bb, X[ 2], 15); 126 | bb = FF(bb, cc, dd, aa, X[ 3], 12); 127 | aa = FF(aa, bb, cc, dd, X[ 4], 5); 128 | dd = FF(dd, aa, bb, cc, X[ 5], 8); 129 | cc = FF(cc, dd, aa, bb, X[ 6], 7); 130 | bb = FF(bb, cc, dd, aa, X[ 7], 9); 131 | aa = FF(aa, bb, cc, dd, X[ 8], 11); 132 | dd = FF(dd, aa, bb, cc, X[ 9], 13); 133 | cc = FF(cc, dd, aa, bb, X[10], 14); 134 | bb = FF(bb, cc, dd, aa, X[11], 15); 135 | aa = FF(aa, bb, cc, dd, X[12], 6); 136 | dd = FF(dd, aa, bb, cc, X[13], 7); 137 | cc = FF(cc, dd, aa, bb, X[14], 9); 138 | bb = FF(bb, cc, dd, aa, X[15], 8); 139 | 140 | aa = GG(aa, bb, cc, dd, X[ 7], 7); 141 | dd = GG(dd, aa, bb, cc, X[ 4], 6); 142 | cc = GG(cc, dd, aa, bb, X[13], 8); 143 | bb = GG(bb, cc, dd, aa, X[ 1], 13); 144 | aa = GG(aa, bb, cc, dd, X[10], 11); 145 | dd = GG(dd, aa, bb, cc, X[ 6], 9); 146 | cc = GG(cc, dd, aa, bb, X[15], 7); 147 | bb = GG(bb, cc, dd, aa, X[ 3], 15); 148 | aa = GG(aa, bb, cc, dd, X[12], 7); 149 | dd = GG(dd, aa, bb, cc, X[ 0], 12); 150 | cc = GG(cc, dd, aa, bb, X[ 9], 15); 151 | bb = GG(bb, cc, dd, aa, X[ 5], 9); 152 | aa = GG(aa, bb, cc, dd, X[ 2], 11); 153 | dd = GG(dd, aa, bb, cc, X[14], 7); 154 | cc = GG(cc, dd, aa, bb, X[11], 13); 155 | bb = GG(bb, cc, dd, aa, X[ 8], 12); 156 | 157 | aa = HH(aa, bb, cc, dd, X[ 3], 11); 158 | dd = HH(dd, aa, bb, cc, X[10], 13); 159 | cc = HH(cc, dd, aa, bb, X[14], 6); 160 | bb = HH(bb, cc, dd, aa, X[ 4], 7); 161 | aa = HH(aa, bb, cc, dd, X[ 9], 14); 162 | dd = HH(dd, aa, bb, cc, X[15], 9); 163 | cc = HH(cc, dd, aa, bb, X[ 8], 13); 164 | bb = HH(bb, cc, dd, aa, X[ 1], 15); 165 | aa = HH(aa, bb, cc, dd, X[ 2], 14); 166 | dd = HH(dd, aa, bb, cc, X[ 7], 8); 167 | cc = HH(cc, dd, aa, bb, X[ 0], 13); 168 | bb = HH(bb, cc, dd, aa, X[ 6], 6); 169 | aa = HH(aa, bb, cc, dd, X[13], 5); 170 | dd = HH(dd, aa, bb, cc, X[11], 12); 171 | cc = HH(cc, dd, aa, bb, X[ 5], 7); 172 | bb = HH(bb, cc, dd, aa, X[12], 5); 173 | 174 | aa = II(aa, bb, cc, dd, X[ 1], 11); 175 | dd = II(dd, aa, bb, cc, X[ 9], 12); 176 | cc = II(cc, dd, aa, bb, X[11], 14); 177 | bb = II(bb, cc, dd, aa, X[10], 15); 178 | aa = II(aa, bb, cc, dd, X[ 0], 14); 179 | dd = II(dd, aa, bb, cc, X[ 8], 15); 180 | cc = II(cc, dd, aa, bb, X[12], 9); 181 | bb = II(bb, cc, dd, aa, X[ 4], 8); 182 | aa = II(aa, bb, cc, dd, X[13], 9); 183 | dd = II(dd, aa, bb, cc, X[ 3], 14); 184 | cc = II(cc, dd, aa, bb, X[ 7], 5); 185 | bb = II(bb, cc, dd, aa, X[15], 6); 186 | aa = II(aa, bb, cc, dd, X[14], 8); 187 | dd = II(dd, aa, bb, cc, X[ 5], 6); 188 | cc = II(cc, dd, aa, bb, X[ 6], 5); 189 | bb = II(bb, cc, dd, aa, X[ 2], 12); 190 | 191 | aaa = III(aaa, bbb, ccc, ddd, X[ 5], 8); 192 | ddd = III(ddd, aaa, bbb, ccc, X[14], 9); 193 | ccc = III(ccc, ddd, aaa, bbb, X[ 7], 9); 194 | bbb = III(bbb, ccc, ddd, aaa, X[ 0], 11); 195 | aaa = III(aaa, bbb, ccc, ddd, X[ 9], 13); 196 | ddd = III(ddd, aaa, bbb, ccc, X[ 2], 15); 197 | ccc = III(ccc, ddd, aaa, bbb, X[11], 15); 198 | bbb = III(bbb, ccc, ddd, aaa, X[ 4], 5); 199 | aaa = III(aaa, bbb, ccc, ddd, X[13], 7); 200 | ddd = III(ddd, aaa, bbb, ccc, X[ 6], 7); 201 | ccc = III(ccc, ddd, aaa, bbb, X[15], 8); 202 | bbb = III(bbb, ccc, ddd, aaa, X[ 8], 11); 203 | aaa = III(aaa, bbb, ccc, ddd, X[ 1], 14); 204 | ddd = III(ddd, aaa, bbb, ccc, X[10], 14); 205 | ccc = III(ccc, ddd, aaa, bbb, X[ 3], 12); 206 | bbb = III(bbb, ccc, ddd, aaa, X[12], 6); 207 | 208 | aaa = HHH(aaa, bbb, ccc, ddd, X[ 6], 9); 209 | ddd = HHH(ddd, aaa, bbb, ccc, X[11], 13); 210 | ccc = HHH(ccc, ddd, aaa, bbb, X[ 3], 15); 211 | bbb = HHH(bbb, ccc, ddd, aaa, X[ 7], 7); 212 | aaa = HHH(aaa, bbb, ccc, ddd, X[ 0], 12); 213 | ddd = HHH(ddd, aaa, bbb, ccc, X[13], 8); 214 | ccc = HHH(ccc, ddd, aaa, bbb, X[ 5], 9); 215 | bbb = HHH(bbb, ccc, ddd, aaa, X[10], 11); 216 | aaa = HHH(aaa, bbb, ccc, ddd, X[14], 7); 217 | ddd = HHH(ddd, aaa, bbb, ccc, X[15], 7); 218 | ccc = HHH(ccc, ddd, aaa, bbb, X[ 8], 12); 219 | bbb = HHH(bbb, ccc, ddd, aaa, X[12], 7); 220 | aaa = HHH(aaa, bbb, ccc, ddd, X[ 4], 6); 221 | ddd = HHH(ddd, aaa, bbb, ccc, X[ 9], 15); 222 | ccc = HHH(ccc, ddd, aaa, bbb, X[ 1], 13); 223 | bbb = HHH(bbb, ccc, ddd, aaa, X[ 2], 11); 224 | 225 | aaa = GGG(aaa, bbb, ccc, ddd, X[15], 9); 226 | ddd = GGG(ddd, aaa, bbb, ccc, X[ 5], 7); 227 | ccc = GGG(ccc, ddd, aaa, bbb, X[ 1], 15); 228 | bbb = GGG(bbb, ccc, ddd, aaa, X[ 3], 11); 229 | aaa = GGG(aaa, bbb, ccc, ddd, X[ 7], 8); 230 | ddd = GGG(ddd, aaa, bbb, ccc, X[14], 6); 231 | ccc = GGG(ccc, ddd, aaa, bbb, X[ 6], 6); 232 | bbb = GGG(bbb, ccc, ddd, aaa, X[ 9], 14); 233 | aaa = GGG(aaa, bbb, ccc, ddd, X[11], 12); 234 | ddd = GGG(ddd, aaa, bbb, ccc, X[ 8], 13); 235 | ccc = GGG(ccc, ddd, aaa, bbb, X[12], 5); 236 | bbb = GGG(bbb, ccc, ddd, aaa, X[ 2], 14); 237 | aaa = GGG(aaa, bbb, ccc, ddd, X[10], 13); 238 | ddd = GGG(ddd, aaa, bbb, ccc, X[ 0], 13); 239 | ccc = GGG(ccc, ddd, aaa, bbb, X[ 4], 7); 240 | bbb = GGG(bbb, ccc, ddd, aaa, X[13], 5); 241 | 242 | aaa = FFF(aaa, bbb, ccc, ddd, X[ 8], 15); 243 | ddd = FFF(ddd, aaa, bbb, ccc, X[ 6], 5); 244 | ccc = FFF(ccc, ddd, aaa, bbb, X[ 4], 8); 245 | bbb = FFF(bbb, ccc, ddd, aaa, X[ 1], 11); 246 | aaa = FFF(aaa, bbb, ccc, ddd, X[ 3], 14); 247 | ddd = FFF(ddd, aaa, bbb, ccc, X[11], 14); 248 | ccc = FFF(ccc, ddd, aaa, bbb, X[15], 6); 249 | bbb = FFF(bbb, ccc, ddd, aaa, X[ 0], 14); 250 | aaa = FFF(aaa, bbb, ccc, ddd, X[ 5], 6); 251 | ddd = FFF(ddd, aaa, bbb, ccc, X[12], 9); 252 | ccc = FFF(ccc, ddd, aaa, bbb, X[ 2], 12); 253 | bbb = FFF(bbb, ccc, ddd, aaa, X[13], 9); 254 | aaa = FFF(aaa, bbb, ccc, ddd, X[ 9], 12); 255 | ddd = FFF(ddd, aaa, bbb, ccc, X[ 7], 5); 256 | ccc = FFF(ccc, ddd, aaa, bbb, X[10], 15); 257 | bbb = FFF(bbb, ccc, ddd, aaa, X[14], 8); 258 | 259 | 260 | A, B, C, D = AND(B + cc + ddd, 0xFFFFFFFF), 261 | AND(C + dd + aaa, 0xFFFFFFFF), 262 | AND(D + aa + bbb, 0xFFFFFFFF), 263 | AND(A + bb + ccc, 0xFFFFFFFF); 264 | 265 | end 266 | 267 | public.init = function() 268 | queue.reset(); 269 | 270 | A = 0x67452301; 271 | B = 0xefcdab89; 272 | C = 0x98badcfe; 273 | D = 0x10325476; 274 | 275 | return public; 276 | end 277 | 278 | 279 | public.update = function(bytes) 280 | for b in bytes do 281 | queue.push(b); 282 | if(queue.size() >= 64) then processBlock(); end 283 | end 284 | 285 | return public; 286 | end 287 | 288 | public.finish = function() 289 | local bits = queue.getHead() * 8; 290 | 291 | queue.push(0x80); 292 | 293 | while ((queue.size() + 7) % 64) < 63 do 294 | queue.push(0x00); 295 | end 296 | 297 | local b0, b1, b2, b3, b4, b5, b6, b7 = dword2bytes(bits); 298 | 299 | queue.push(b0); 300 | queue.push(b1); 301 | queue.push(b2); 302 | queue.push(b3); 303 | queue.push(b4); 304 | queue.push(b5); 305 | queue.push(b6); 306 | queue.push(b7); 307 | 308 | while queue.size() > 0 do 309 | processBlock(); 310 | end 311 | 312 | return public; 313 | end 314 | 315 | public.asBytes = function() 316 | local b0, b1, b2, b3 = word2bytes(A); 317 | local b4, b5, b6, b7 = word2bytes(B); 318 | local b8, b9, b10, b11 = word2bytes(C); 319 | local b12, b13, b14, b15 = word2bytes(D); 320 | 321 | return { b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, 322 | b10, b11, b12, b13, b14, b15}; 323 | end 324 | 325 | public.asHex = function() 326 | local b0, b1, b2, b3 = word2bytes(A); 327 | local b4, b5, b6, b7 = word2bytes(B); 328 | local b8, b9, b10, b11 = word2bytes(C); 329 | local b12, b13, b14, b15 = word2bytes(D); 330 | 331 | local fmt = "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"; 332 | 333 | return String.format(fmt, 334 | b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, 335 | b10, b11, b12, b13, b14, b15); 336 | end 337 | 338 | public.asString = function() 339 | local b0, b1, b2, b3 = word2bytes(A); 340 | local b4, b5, b6, b7 = word2bytes(B); 341 | local b8, b9, b10, b11 = word2bytes(C); 342 | local b12, b13, b14, b15 = word2bytes(D); 343 | 344 | return string.pack(string.rep('B', 16), 345 | b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, 346 | b10, b11, b12, b13, b14, b15); 347 | end 348 | 349 | return public; 350 | 351 | end 352 | 353 | return RIPEMD128; 354 | 355 | -------------------------------------------------------------------------------- /lockbox/digest/sha1.lua: -------------------------------------------------------------------------------- 1 | require("lockbox").insecure(); 2 | 3 | local Bit = require("lockbox.util.bit"); 4 | local String = require("string"); 5 | local Math = require("math"); 6 | local Queue = require("lockbox.util.queue"); 7 | 8 | local AND = Bit.band; 9 | local OR = Bit.bor; 10 | local XOR = Bit.bxor; 11 | local LROT = Bit.lrotate; 12 | local LSHIFT = Bit.lshift; 13 | local RSHIFT = Bit.rshift; 14 | 15 | --SHA1 is big-endian 16 | local bytes2word = function(b0, b1, b2, b3) 17 | local i = b0; i = LSHIFT(i, 8); 18 | i = OR(i, b1); i = LSHIFT(i, 8); 19 | i = OR(i, b2); i = LSHIFT(i, 8); 20 | i = OR(i, b3); 21 | return i; 22 | end 23 | 24 | local word2bytes = function(word) 25 | local b0, b1, b2, b3; 26 | b3 = AND(word, 0xFF); word = RSHIFT(word, 8); 27 | b2 = AND(word, 0xFF); word = RSHIFT(word, 8); 28 | b1 = AND(word, 0xFF); word = RSHIFT(word, 8); 29 | b0 = AND(word, 0xFF); 30 | return b0, b1, b2, b3; 31 | end 32 | 33 | local dword2bytes = function(i) 34 | local b4, b5, b6, b7 = word2bytes(i); 35 | local b0, b1, b2, b3 = word2bytes(Math.floor(i / 0x100000000)); 36 | return b0, b1, b2, b3, b4, b5, b6, b7; 37 | end 38 | 39 | local F = function(x, y, z) return XOR(z, AND(x, XOR(y, z))); end 40 | local G = function(x, y, z) return XOR(x, XOR(y, z)); end 41 | local H = function(x, y, z) return OR(AND(x, OR(y, z)), AND(y, z)); end 42 | local I = function(x, y, z) return XOR(x, XOR(y, z)); end 43 | 44 | local SHA1 = function() 45 | 46 | local queue = Queue(); 47 | 48 | local h0 = 0x67452301; 49 | local h1 = 0xEFCDAB89; 50 | local h2 = 0x98BADCFE; 51 | local h3 = 0x10325476; 52 | local h4 = 0xC3D2E1F0; 53 | 54 | local public = {}; 55 | 56 | local processBlock = function() 57 | local a = h0; 58 | local b = h1; 59 | local c = h2; 60 | local d = h3; 61 | local e = h4; 62 | local temp; 63 | local k; 64 | 65 | local w = {}; 66 | for i = 0, 15 do 67 | w[i] = bytes2word(queue.pop(), queue.pop(), queue.pop(), queue.pop()); 68 | end 69 | 70 | for i = 16, 79 do 71 | w[i] = LROT((XOR(XOR(w[i - 3], w[i - 8]), XOR(w[i - 14], w[i - 16]))), 1); 72 | end 73 | 74 | for i = 0, 79 do 75 | if (i <= 19) then 76 | temp = F(b, c, d); 77 | k = 0x5A827999; 78 | elseif (i <= 39) then 79 | temp = G(b, c, d); 80 | k = 0x6ED9EBA1; 81 | elseif (i <= 59) then 82 | temp = H(b, c, d); 83 | k = 0x8F1BBCDC; 84 | else 85 | temp = I(b, c, d); 86 | k = 0xCA62C1D6; 87 | end 88 | temp = LROT(a, 5) + temp + e + k + w[i]; 89 | e = d; 90 | d = c; 91 | c = LROT(b, 30); 92 | b = a; 93 | a = temp; 94 | end 95 | 96 | h0 = AND(h0 + a, 0xFFFFFFFF); 97 | h1 = AND(h1 + b, 0xFFFFFFFF); 98 | h2 = AND(h2 + c, 0xFFFFFFFF); 99 | h3 = AND(h3 + d, 0xFFFFFFFF); 100 | h4 = AND(h4 + e, 0xFFFFFFFF); 101 | end 102 | 103 | public.init = function() 104 | queue.reset(); 105 | h0 = 0x67452301; 106 | h1 = 0xEFCDAB89; 107 | h2 = 0x98BADCFE; 108 | h3 = 0x10325476; 109 | h4 = 0xC3D2E1F0; 110 | return public; 111 | end 112 | 113 | 114 | public.update = function(bytes) 115 | for b in bytes do 116 | queue.push(b); 117 | if queue.size() >= 64 then processBlock(); end 118 | end 119 | 120 | return public; 121 | end 122 | 123 | public.finish = function() 124 | local bits = queue.getHead() * 8; 125 | 126 | queue.push(0x80); 127 | while ((queue.size() + 7) % 64) < 63 do 128 | queue.push(0x00); 129 | end 130 | 131 | local b0, b1, b2, b3, b4, b5, b6, b7 = dword2bytes(bits); 132 | 133 | queue.push(b0); 134 | queue.push(b1); 135 | queue.push(b2); 136 | queue.push(b3); 137 | queue.push(b4); 138 | queue.push(b5); 139 | queue.push(b6); 140 | queue.push(b7); 141 | 142 | while queue.size() > 0 do 143 | processBlock(); 144 | end 145 | 146 | return public; 147 | end 148 | 149 | public.asBytes = function() 150 | local b0, b1, b2, b3 = word2bytes(h0); 151 | local b4, b5, b6, b7 = word2bytes(h1); 152 | local b8, b9, b10, b11 = word2bytes(h2); 153 | local b12, b13, b14, b15 = word2bytes(h3); 154 | local b16, b17, b18, b19 = word2bytes(h4); 155 | 156 | return {b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19}; 157 | end 158 | 159 | public.asHex = function() 160 | local b0, b1, b2, b3 = word2bytes(h0); 161 | local b4, b5, b6, b7 = word2bytes(h1); 162 | local b8, b9, b10, b11 = word2bytes(h2); 163 | local b12, b13, b14, b15 = word2bytes(h3); 164 | local b16, b17, b18, b19 = word2bytes(h4); 165 | 166 | return String.format("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 167 | b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19); 168 | end 169 | 170 | public.asString = function() 171 | local b0, b1, b2, b3 = word2bytes(h0); 172 | local b4, b5, b6, b7 = word2bytes(h1); 173 | local b8, b9, b10, b11 = word2bytes(h2); 174 | local b12, b13, b14, b15 = word2bytes(h3); 175 | local b16, b17, b18, b19 = word2bytes(h4); 176 | 177 | return string.pack(string.rep('B', 20), 178 | b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19); 179 | end 180 | 181 | return public; 182 | end 183 | 184 | return SHA1; 185 | -------------------------------------------------------------------------------- /lockbox/digest/sha2_224.lua: -------------------------------------------------------------------------------- 1 | local Bit = require("lockbox.util.bit"); 2 | local String = require("string"); 3 | local Math = require("math"); 4 | local Queue = require("lockbox.util.queue"); 5 | 6 | local CONSTANTS = { 7 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 8 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 9 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 10 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 11 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 12 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 13 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 14 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; 15 | 16 | local fmt = "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" .. 17 | "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" 18 | 19 | local AND = Bit.band; 20 | local OR = Bit.bor; 21 | local NOT = Bit.bnot; 22 | local XOR = Bit.bxor; 23 | local RROT = Bit.rrotate; 24 | local LSHIFT = Bit.lshift; 25 | local RSHIFT = Bit.rshift; 26 | 27 | --SHA2 is big-endian 28 | local bytes2word = function(b0, b1, b2, b3) 29 | local i = b0; i = LSHIFT(i, 8); 30 | i = OR(i, b1); i = LSHIFT(i, 8); 31 | i = OR(i, b2); i = LSHIFT(i, 8); 32 | i = OR(i, b3); 33 | return i; 34 | end 35 | 36 | local word2bytes = function(word) 37 | local b0, b1, b2, b3; 38 | b3 = AND(word, 0xFF); word = RSHIFT(word, 8); 39 | b2 = AND(word, 0xFF); word = RSHIFT(word, 8); 40 | b1 = AND(word, 0xFF); word = RSHIFT(word, 8); 41 | b0 = AND(word, 0xFF); 42 | return b0, b1, b2, b3; 43 | end 44 | 45 | local dword2bytes = function(i) 46 | local b4, b5, b6, b7 = word2bytes(i); 47 | local b0, b1, b2, b3 = word2bytes(Math.floor(i / 0x100000000)); 48 | return b0, b1, b2, b3, b4, b5, b6, b7; 49 | end 50 | 51 | 52 | 53 | 54 | local SHA2_224 = function() 55 | 56 | local queue = Queue(); 57 | 58 | local h0 = 0xc1059ed8; 59 | local h1 = 0x367cd507; 60 | local h2 = 0x3070dd17; 61 | local h3 = 0xf70e5939; 62 | local h4 = 0xffc00b31; 63 | local h5 = 0x68581511; 64 | local h6 = 0x64f98fa7; 65 | local h7 = 0xbefa4fa4; 66 | 67 | local public = {}; 68 | 69 | local processBlock = function() 70 | local a = h0; 71 | local b = h1; 72 | local c = h2; 73 | local d = h3; 74 | local e = h4; 75 | local f = h5; 76 | local g = h6; 77 | local h = h7; 78 | 79 | local w = {}; 80 | 81 | for i = 0, 15 do 82 | w[i] = bytes2word(queue.pop(), queue.pop(), queue.pop(), queue.pop()); 83 | end 84 | 85 | for i = 16, 63 do 86 | local s0 = XOR(RROT(w[i - 15], 7), XOR(RROT(w[i - 15], 18), RSHIFT(w[i - 15], 3))); 87 | local s1 = XOR(RROT(w[i - 2], 17), XOR(RROT(w[i - 2], 19), RSHIFT(w[i - 2], 10))); 88 | w[i] = AND(w[i - 16] + s0 + w[i - 7] + s1, 0xFFFFFFFF); 89 | end 90 | 91 | for i = 0, 63 do 92 | local s1 = XOR(RROT(e, 6), XOR(RROT(e, 11), RROT(e, 25))); 93 | local ch = XOR(AND(e, f), AND(NOT(e), g)); 94 | local temp1 = h + s1 + ch + CONSTANTS[i + 1] + w[i]; 95 | local s0 = XOR(RROT(a, 2), XOR(RROT(a, 13), RROT(a, 22))); 96 | local maj = XOR(AND(a, b), XOR(AND(a, c), AND(b, c))); 97 | local temp2 = s0 + maj; 98 | 99 | h = g; 100 | g = f; 101 | f = e; 102 | e = d + temp1; 103 | d = c; 104 | c = b; 105 | b = a; 106 | a = temp1 + temp2; 107 | end 108 | 109 | h0 = AND(h0 + a, 0xFFFFFFFF); 110 | h1 = AND(h1 + b, 0xFFFFFFFF); 111 | h2 = AND(h2 + c, 0xFFFFFFFF); 112 | h3 = AND(h3 + d, 0xFFFFFFFF); 113 | h4 = AND(h4 + e, 0xFFFFFFFF); 114 | h5 = AND(h5 + f, 0xFFFFFFFF); 115 | h6 = AND(h6 + g, 0xFFFFFFFF); 116 | h7 = AND(h7 + h, 0xFFFFFFFF); 117 | end 118 | 119 | public.init = function() 120 | queue.reset(); 121 | 122 | h0 = 0xc1059ed8; 123 | h1 = 0x367cd507; 124 | h2 = 0x3070dd17; 125 | h3 = 0xf70e5939; 126 | h4 = 0xffc00b31; 127 | h5 = 0x68581511; 128 | h6 = 0x64f98fa7; 129 | h7 = 0xbefa4fa4; 130 | 131 | return public; 132 | end 133 | 134 | public.update = function(bytes) 135 | for b in bytes do 136 | queue.push(b); 137 | if queue.size() >= 64 then processBlock(); end 138 | end 139 | 140 | return public; 141 | end 142 | 143 | public.finish = function() 144 | local bits = queue.getHead() * 8; 145 | 146 | queue.push(0x80); 147 | while ((queue.size() + 7) % 64) < 63 do 148 | queue.push(0x00); 149 | end 150 | 151 | local b0, b1, b2, b3, b4, b5, b6, b7 = dword2bytes(bits); 152 | 153 | queue.push(b0); 154 | queue.push(b1); 155 | queue.push(b2); 156 | queue.push(b3); 157 | queue.push(b4); 158 | queue.push(b5); 159 | queue.push(b6); 160 | queue.push(b7); 161 | 162 | while queue.size() > 0 do 163 | processBlock(); 164 | end 165 | 166 | return public; 167 | end 168 | 169 | public.asBytes = function() 170 | local b0, b1, b2, b3 = word2bytes(h0); 171 | local b4, b5, b6, b7 = word2bytes(h1); 172 | local b8, b9, b10, b11 = word2bytes(h2); 173 | local b12, b13, b14, b15 = word2bytes(h3); 174 | local b16, b17, b18, b19 = word2bytes(h4); 175 | local b20, b21, b22, b23 = word2bytes(h5); 176 | local b24, b25, b26, b27 = word2bytes(h6); 177 | 178 | return { b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 179 | , b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27}; 180 | end 181 | 182 | public.asHex = function() 183 | local b0, b1, b2, b3 = word2bytes(h0); 184 | local b4, b5, b6, b7 = word2bytes(h1); 185 | local b8, b9, b10, b11 = word2bytes(h2); 186 | local b12, b13, b14, b15 = word2bytes(h3); 187 | local b16, b17, b18, b19 = word2bytes(h4); 188 | local b20, b21, b22, b23 = word2bytes(h5); 189 | local b24, b25, b26, b27 = word2bytes(h6); 190 | 191 | return String.format(fmt, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 192 | , b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27); 193 | end 194 | 195 | public.asString = function() 196 | local b0, b1, b2, b3 = word2bytes(h0); 197 | local b4, b5, b6, b7 = word2bytes(h1); 198 | local b8, b9, b10, b11 = word2bytes(h2); 199 | local b12, b13, b14, b15 = word2bytes(h3); 200 | local b16, b17, b18, b19 = word2bytes(h4); 201 | local b20, b21, b22, b23 = word2bytes(h5); 202 | local b24, b25, b26, b27 = word2bytes(h6); 203 | 204 | return string.pack(string.rep('B', 28), 205 | b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, 206 | b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27); 207 | end 208 | 209 | return public; 210 | 211 | end 212 | 213 | return SHA2_224; 214 | 215 | -------------------------------------------------------------------------------- /lockbox/digest/sha2_256.lua: -------------------------------------------------------------------------------- 1 | local Bit = require("lockbox.util.bit"); 2 | local String = require("string"); 3 | local Math = require("math"); 4 | local Queue = require("lockbox.util.queue"); 5 | 6 | local CONSTANTS = { 7 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 8 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 9 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 10 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 11 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 12 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 13 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 14 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; 15 | 16 | local fmt = "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" .. 17 | "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" 18 | 19 | local AND = Bit.band; 20 | local OR = Bit.bor; 21 | local NOT = Bit.bnot; 22 | local XOR = Bit.bxor; 23 | local RROT = Bit.rrotate; 24 | local LSHIFT = Bit.lshift; 25 | local RSHIFT = Bit.rshift; 26 | 27 | --SHA2 is big-endian 28 | local bytes2word = function(b0, b1, b2, b3) 29 | local i = b0; i = LSHIFT(i, 8); 30 | i = OR(i, b1); i = LSHIFT(i, 8); 31 | i = OR(i, b2); i = LSHIFT(i, 8); 32 | i = OR(i, b3); 33 | return i; 34 | end 35 | 36 | local word2bytes = function(word) 37 | local b0, b1, b2, b3; 38 | b3 = AND(word, 0xFF); word = RSHIFT(word, 8); 39 | b2 = AND(word, 0xFF); word = RSHIFT(word, 8); 40 | b1 = AND(word, 0xFF); word = RSHIFT(word, 8); 41 | b0 = AND(word, 0xFF); 42 | return b0, b1, b2, b3; 43 | end 44 | 45 | local dword2bytes = function(i) 46 | local b4, b5, b6, b7 = word2bytes(i); 47 | local b0, b1, b2, b3 = word2bytes(Math.floor(i / 0x100000000)); 48 | return b0, b1, b2, b3, b4, b5, b6, b7; 49 | end 50 | 51 | 52 | 53 | 54 | local SHA2_256 = function() 55 | 56 | local queue = Queue(); 57 | 58 | local h0 = 0x6a09e667; 59 | local h1 = 0xbb67ae85; 60 | local h2 = 0x3c6ef372; 61 | local h3 = 0xa54ff53a; 62 | local h4 = 0x510e527f; 63 | local h5 = 0x9b05688c; 64 | local h6 = 0x1f83d9ab; 65 | local h7 = 0x5be0cd19; 66 | 67 | local public = {}; 68 | 69 | local processBlock = function() 70 | local a = h0; 71 | local b = h1; 72 | local c = h2; 73 | local d = h3; 74 | local e = h4; 75 | local f = h5; 76 | local g = h6; 77 | local h = h7; 78 | 79 | local w = {}; 80 | 81 | for i = 0, 15 do 82 | w[i] = bytes2word(queue.pop(), queue.pop(), queue.pop(), queue.pop()); 83 | end 84 | 85 | for i = 16, 63 do 86 | local s0 = XOR(RROT(w[i - 15], 7), XOR(RROT(w[i - 15], 18), RSHIFT(w[i - 15], 3))); 87 | local s1 = XOR(RROT(w[i - 2], 17), XOR(RROT(w[i - 2], 19), RSHIFT(w[i - 2], 10))); 88 | w[i] = AND(w[i - 16] + s0 + w[i - 7] + s1, 0xFFFFFFFF); 89 | end 90 | 91 | for i = 0, 63 do 92 | local s1 = XOR(RROT(e, 6), XOR(RROT(e, 11), RROT(e, 25))); 93 | local ch = XOR(AND(e, f), AND(NOT(e), g)); 94 | local temp1 = h + s1 + ch + CONSTANTS[i + 1] + w[i]; 95 | local s0 = XOR(RROT(a, 2), XOR(RROT(a, 13), RROT(a, 22))); 96 | local maj = XOR(AND(a, b), XOR(AND(a, c), AND(b, c))); 97 | local temp2 = s0 + maj; 98 | 99 | h = g; 100 | g = f; 101 | f = e; 102 | e = d + temp1; 103 | d = c; 104 | c = b; 105 | b = a; 106 | a = temp1 + temp2; 107 | end 108 | 109 | h0 = AND(h0 + a, 0xFFFFFFFF); 110 | h1 = AND(h1 + b, 0xFFFFFFFF); 111 | h2 = AND(h2 + c, 0xFFFFFFFF); 112 | h3 = AND(h3 + d, 0xFFFFFFFF); 113 | h4 = AND(h4 + e, 0xFFFFFFFF); 114 | h5 = AND(h5 + f, 0xFFFFFFFF); 115 | h6 = AND(h6 + g, 0xFFFFFFFF); 116 | h7 = AND(h7 + h, 0xFFFFFFFF); 117 | end 118 | 119 | public.init = function() 120 | queue.reset(); 121 | 122 | h0 = 0x6a09e667; 123 | h1 = 0xbb67ae85; 124 | h2 = 0x3c6ef372; 125 | h3 = 0xa54ff53a; 126 | h4 = 0x510e527f; 127 | h5 = 0x9b05688c; 128 | h6 = 0x1f83d9ab; 129 | h7 = 0x5be0cd19; 130 | 131 | return public; 132 | end 133 | 134 | public.update = function(bytes) 135 | for b in bytes do 136 | queue.push(b); 137 | if queue.size() >= 64 then processBlock(); end 138 | end 139 | 140 | return public; 141 | end 142 | 143 | public.finish = function() 144 | local bits = queue.getHead() * 8; 145 | 146 | queue.push(0x80); 147 | while ((queue.size() + 7) % 64) < 63 do 148 | queue.push(0x00); 149 | end 150 | 151 | local b0, b1, b2, b3, b4, b5, b6, b7 = dword2bytes(bits); 152 | 153 | queue.push(b0); 154 | queue.push(b1); 155 | queue.push(b2); 156 | queue.push(b3); 157 | queue.push(b4); 158 | queue.push(b5); 159 | queue.push(b6); 160 | queue.push(b7); 161 | 162 | while queue.size() > 0 do 163 | processBlock(); 164 | end 165 | 166 | return public; 167 | end 168 | 169 | public.asBytes = function() 170 | local b0, b1, b2, b3 = word2bytes(h0); 171 | local b4, b5, b6, b7 = word2bytes(h1); 172 | local b8, b9, b10, b11 = word2bytes(h2); 173 | local b12, b13, b14, b15 = word2bytes(h3); 174 | local b16, b17, b18, b19 = word2bytes(h4); 175 | local b20, b21, b22, b23 = word2bytes(h5); 176 | local b24, b25, b26, b27 = word2bytes(h6); 177 | local b28, b29, b30, b31 = word2bytes(h7); 178 | 179 | 180 | return { b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 181 | , b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31}; 182 | end 183 | 184 | public.asHex = function() 185 | local b0, b1, b2, b3 = word2bytes(h0); 186 | local b4, b5, b6, b7 = word2bytes(h1); 187 | local b8, b9, b10, b11 = word2bytes(h2); 188 | local b12, b13, b14, b15 = word2bytes(h3); 189 | local b16, b17, b18, b19 = word2bytes(h4); 190 | local b20, b21, b22, b23 = word2bytes(h5); 191 | local b24, b25, b26, b27 = word2bytes(h6); 192 | local b28, b29, b30, b31 = word2bytes(h7); 193 | 194 | return String.format(fmt, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 195 | , b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31); 196 | end 197 | 198 | public.asString = function() 199 | local b0, b1, b2, b3 = word2bytes(h0); 200 | local b4, b5, b6, b7 = word2bytes(h1); 201 | local b8, b9, b10, b11 = word2bytes(h2); 202 | local b12, b13, b14, b15 = word2bytes(h3); 203 | local b16, b17, b18, b19 = word2bytes(h4); 204 | local b20, b21, b22, b23 = word2bytes(h5); 205 | local b24, b25, b26, b27 = word2bytes(h6); 206 | local b28, b29, b30, b31 = word2bytes(h7); 207 | 208 | return string.pack(string.rep('B', 32), 209 | b0, b1, b2, b3, b4, b5, b6, b7, b8, 210 | b9, b10, b11, b12, b13, b14, b15, 211 | b16, b17, b18, b19, b20, b21, b22, b23, b24, 212 | b25, b26, b27, b28, b29, b30, b31); 213 | end 214 | 215 | return public; 216 | 217 | end 218 | 219 | return SHA2_256; 220 | 221 | -------------------------------------------------------------------------------- /lockbox/init.lua: -------------------------------------------------------------------------------- 1 | local Lockbox = {}; 2 | 3 | --[[ 4 | package.path = "./?.lua;" 5 | .. "./cipher/?.lua;" 6 | .. "./digest/?.lua;" 7 | .. "./kdf/?.lua;" 8 | .. "./mac/?.lua;" 9 | .. "./padding/?.lua;" 10 | .. "./test/?.lua;" 11 | .. "./util/?.lua;" 12 | .. package.path; 13 | --]] 14 | Lockbox.ALLOW_INSECURE = false; 15 | 16 | Lockbox.insecure = function() 17 | assert(Lockbox.ALLOW_INSECURE, 18 | "This module is insecure! It should not be used in production." .. 19 | "If you really want to use it, set Lockbox.ALLOW_INSECURE to true before importing it"); 20 | end 21 | 22 | return Lockbox; 23 | -------------------------------------------------------------------------------- /lockbox/kdf/hkdf.lua: -------------------------------------------------------------------------------- 1 | local HMAC = require("lockbox.mac.hmac"); 2 | 3 | local Stream = require("lockbox.util.stream"); 4 | local Array = require("lockbox.util.array"); 5 | 6 | local HKDF = function() 7 | 8 | local public = {}; 9 | 10 | local Digest = nil; 11 | local inputKeyMaterial; 12 | local salt = Array.fromHex("0000000000000000000000000000000000000000"); 13 | local info; 14 | local outputLen; 15 | 16 | local hashLen; 17 | local secret; 18 | 19 | local extract = function() 20 | local res = HMAC() 21 | .setDigest(Digest) 22 | .setKey(salt) 23 | .init() 24 | .update(Stream.fromArray(inputKeyMaterial)) 25 | .finish() 26 | .asBytes(); 27 | hashLen = #res; 28 | return res; 29 | end 30 | 31 | local expand = function(prk) 32 | local iterations = math.ceil(outputLen / hashLen); 33 | local mixin = {}; 34 | local results = {}; 35 | local remainingBytes = outputLen; 36 | 37 | for i = 1, iterations do 38 | local mac = HMAC() 39 | .setDigest(Digest) 40 | .setKey(prk) 41 | .init(); 42 | 43 | mac.update(Stream.fromArray(mixin)); 44 | if info then 45 | mac.update(Stream.fromArray(info)); 46 | end 47 | mac.update(Stream.fromArray({ i })); 48 | 49 | local stepResult = mac.finish().asBytes(); 50 | local stepSize = math.min(remainingBytes, #stepResult); 51 | 52 | for j = 1, stepSize do 53 | results[#results + 1] = stepResult[j]; 54 | end 55 | 56 | mixin = stepResult; 57 | remainingBytes = remainingBytes - stepSize; 58 | end 59 | 60 | return results; 61 | end 62 | 63 | public.setDigest = function(digestModule) 64 | Digest = digestModule; 65 | return public; 66 | end 67 | 68 | public.setInputKeyMaterial = function(ikm) 69 | inputKeyMaterial = ikm; 70 | return public; 71 | end 72 | 73 | public.setSalt = function(s) 74 | salt = s or salt; 75 | return public; 76 | end 77 | 78 | public.setInfo = function(i) 79 | info = i; 80 | return public; 81 | end 82 | 83 | public.setOutputLen = function(len) 84 | outputLen = len; 85 | return public; 86 | end 87 | 88 | public.finish = function() 89 | local prk = extract(salt, inputKeyMaterial); 90 | secret = expand(prk, info); 91 | return public; 92 | end 93 | 94 | public.asBytes = function() 95 | return secret; 96 | end 97 | 98 | public.asHex = function() 99 | return Array.toHex(secret); 100 | end 101 | 102 | public.asString = function() 103 | return Array.toString(secret); 104 | end 105 | 106 | return public; 107 | end 108 | 109 | return HKDF; 110 | -------------------------------------------------------------------------------- /lockbox/kdf/pbkdf2.lua: -------------------------------------------------------------------------------- 1 | local Bit = require("lockbox.util.bit"); 2 | local Array = require("lockbox.util.array"); 3 | local Stream = require("lockbox.util.stream"); 4 | local Math = require("math"); 5 | 6 | local AND = Bit.band; 7 | local RSHIFT = Bit.rshift; 8 | 9 | local word2bytes = function(word) 10 | local b0, b1, b2, b3; 11 | b3 = AND(word, 0xFF); word = RSHIFT(word, 8); 12 | b2 = AND(word, 0xFF); word = RSHIFT(word, 8); 13 | b1 = AND(word, 0xFF); word = RSHIFT(word, 8); 14 | b0 = AND(word, 0xFF); 15 | return b0, b1, b2, b3; 16 | end 17 | 18 | local PBKDF2 = function() 19 | 20 | local public = {}; 21 | 22 | local blockLen = 16; 23 | local dKeyLen = 256; 24 | local iterations = 4096; 25 | 26 | local salt; 27 | local password; 28 | 29 | 30 | local PRF; 31 | 32 | local dKey; 33 | 34 | 35 | public.setBlockLen = function(len) 36 | blockLen = len; 37 | return public; 38 | end 39 | 40 | public.setDKeyLen = function(len) 41 | dKeyLen = len 42 | return public; 43 | end 44 | 45 | public.setIterations = function(iter) 46 | iterations = iter; 47 | return public; 48 | end 49 | 50 | public.setSalt = function(saltBytes) 51 | salt = saltBytes; 52 | return public; 53 | end 54 | 55 | public.setPassword = function(passwordBytes) 56 | password = passwordBytes; 57 | return public; 58 | end 59 | 60 | public.setPRF = function(prf) 61 | PRF = prf; 62 | return public; 63 | end 64 | 65 | local buildBlock = function(i) 66 | local b0, b1, b2, b3 = word2bytes(i); 67 | local ii = {b0, b1, b2, b3}; 68 | local s = Array.concat(salt, ii); 69 | 70 | local out = {}; 71 | 72 | PRF.setKey(password); 73 | for c = 1, iterations do 74 | PRF.init() 75 | .update(Stream.fromArray(s)); 76 | 77 | s = PRF.finish().asBytes(); 78 | if(c > 1) then 79 | out = Array.XOR(out, s); 80 | else 81 | out = s; 82 | end 83 | end 84 | 85 | return out; 86 | end 87 | 88 | public.finish = function() 89 | local blocks = Math.ceil(dKeyLen / blockLen); 90 | 91 | dKey = {}; 92 | 93 | for b = 1, blocks do 94 | local block = buildBlock(b); 95 | dKey = Array.concat(dKey, block); 96 | end 97 | 98 | if(Array.size(dKey) > dKeyLen) then dKey = Array.truncate(dKey, dKeyLen); end 99 | 100 | return public; 101 | end 102 | 103 | public.asBytes = function() 104 | return dKey; 105 | end 106 | 107 | public.asHex = function() 108 | return Array.toHex(dKey); 109 | end 110 | 111 | public.asString = function() 112 | return Array.toString(dKey); 113 | end 114 | 115 | return public; 116 | end 117 | 118 | return PBKDF2; 119 | -------------------------------------------------------------------------------- /lockbox/mac/hmac.lua: -------------------------------------------------------------------------------- 1 | local Bit = require("lockbox.util.bit"); 2 | local Stream = require("lockbox.util.stream"); 3 | local Array = require("lockbox.util.array"); 4 | 5 | local XOR = Bit.bxor; 6 | 7 | local HMAC = function() 8 | 9 | local public = {}; 10 | local blockSize = 64; 11 | local Digest = nil; 12 | local outerPadding = {}; 13 | local innerPadding = {} 14 | local digest; 15 | 16 | public.setBlockSize = function(bytes) 17 | blockSize = bytes; 18 | return public; 19 | end 20 | 21 | public.setDigest = function(digestModule) 22 | Digest = digestModule; 23 | digest = Digest(); 24 | return public; 25 | end 26 | 27 | public.setKey = function(key) 28 | local keyStream; 29 | 30 | if(Array.size(key) > blockSize) then 31 | keyStream = Stream.fromArray(Digest() 32 | .update(Stream.fromArray(key)) 33 | .finish() 34 | .asBytes()); 35 | else 36 | keyStream = Stream.fromArray(key); 37 | end 38 | 39 | outerPadding = {}; 40 | innerPadding = {}; 41 | 42 | for i = 1, blockSize do 43 | local byte = keyStream(); 44 | if byte == nil then byte = 0x00; end 45 | outerPadding[i] = XOR(0x5C, byte); 46 | innerPadding[i] = XOR(0x36, byte); 47 | end 48 | 49 | return public; 50 | end 51 | 52 | public.init = function() 53 | digest.init() 54 | .update(Stream.fromArray(innerPadding)); 55 | return public; 56 | end 57 | 58 | public.update = function(messageStream) 59 | digest.update(messageStream); 60 | return public; 61 | end 62 | 63 | public.finish = function() 64 | local inner = digest.finish().asBytes(); 65 | digest.init() 66 | .update(Stream.fromArray(outerPadding)) 67 | .update(Stream.fromArray(inner)) 68 | .finish(); 69 | 70 | return public; 71 | end 72 | 73 | public.asBytes = function() 74 | return digest.asBytes(); 75 | end 76 | 77 | public.asHex = function() 78 | return digest.asHex(); 79 | end 80 | 81 | public.asString = function() 82 | return digest.asString(); 83 | end 84 | 85 | return public; 86 | 87 | end 88 | 89 | return HMAC; 90 | -------------------------------------------------------------------------------- /lockbox/padding/ansix923.lua: -------------------------------------------------------------------------------- 1 | local ANSIX923Padding = function(blockSize, byteCount) 2 | 3 | local paddingCount = blockSize - (byteCount % blockSize); 4 | local bytesLeft = paddingCount; 5 | 6 | local stream = function() 7 | if bytesLeft > 1 then 8 | bytesLeft = bytesLeft - 1; 9 | return 0x00; 10 | elseif bytesLeft > 0 then 11 | bytesLeft = bytesLeft - 1; 12 | return paddingCount; 13 | else 14 | return nil; 15 | end 16 | end 17 | 18 | return stream; 19 | 20 | end 21 | 22 | return ANSIX923Padding; 23 | -------------------------------------------------------------------------------- /lockbox/padding/isoiec7816.lua: -------------------------------------------------------------------------------- 1 | local ISOIEC7816Padding = function(blockSize, byteCount) 2 | 3 | local paddingCount = blockSize - (byteCount % blockSize); 4 | local bytesLeft = paddingCount; 5 | 6 | local stream = function() 7 | if bytesLeft == paddingCount then 8 | bytesLeft = bytesLeft - 1; 9 | return 0x80; 10 | elseif bytesLeft > 0 then 11 | bytesLeft = bytesLeft - 1; 12 | return 0x00; 13 | else 14 | return nil; 15 | end 16 | end 17 | 18 | return stream; 19 | 20 | end 21 | 22 | return ISOIEC7816Padding; 23 | -------------------------------------------------------------------------------- /lockbox/padding/pkcs7.lua: -------------------------------------------------------------------------------- 1 | local PKCS7Padding = function(blockSize, byteCount) 2 | local paddingCount = blockSize - (((byteCount - 1) % blockSize) + 1); 3 | local bytesLeft = paddingCount; 4 | 5 | local stream = function() 6 | if bytesLeft > 0 then 7 | bytesLeft = bytesLeft - 1; 8 | return paddingCount; 9 | else 10 | return nil; 11 | end 12 | end 13 | 14 | return stream; 15 | end 16 | 17 | return PKCS7Padding; 18 | -------------------------------------------------------------------------------- /lockbox/padding/zero.lua: -------------------------------------------------------------------------------- 1 | local ZeroPadding = function(blockSize, byteCount) 2 | 3 | local paddingCount = blockSize - ((byteCount -1) % blockSize) + 1; 4 | local bytesLeft = paddingCount; 5 | 6 | local stream = function() 7 | if bytesLeft > 0 then 8 | bytesLeft = bytesLeft - 1; 9 | return 0x00; 10 | else 11 | return nil; 12 | end 13 | end 14 | 15 | return stream; 16 | 17 | end 18 | 19 | return ZeroPadding; 20 | -------------------------------------------------------------------------------- /lockbox/util/array.lua: -------------------------------------------------------------------------------- 1 | 2 | local String = require("string"); 3 | local Bit = require("lockbox.util.bit"); 4 | local Queue = require("lockbox.util.queue"); 5 | 6 | local XOR = Bit.bxor; 7 | 8 | local Array = {}; 9 | 10 | Array.size = function(array) 11 | return #array; 12 | end 13 | 14 | Array.fromString = function(string) 15 | local bytes = {}; 16 | 17 | local i = 1; 18 | local byte = String.byte(string, i); 19 | while byte ~= nil do 20 | bytes[i] = byte; 21 | i = i + 1; 22 | byte = String.byte(string, i); 23 | end 24 | 25 | return bytes; 26 | 27 | end 28 | 29 | Array.toString = function(bytes) 30 | local chars = {}; 31 | local i = 1; 32 | 33 | local byte = bytes[i]; 34 | while byte ~= nil do 35 | chars[i] = String.char(byte); 36 | i = i + 1; 37 | byte = bytes[i]; 38 | end 39 | 40 | return table.concat(chars, ""); 41 | end 42 | 43 | Array.fromStream = function(stream) 44 | local array = {}; 45 | local i = 1; 46 | 47 | local byte = stream(); 48 | while byte ~= nil do 49 | array[i] = byte; 50 | i = i + 1; 51 | byte = stream(); 52 | end 53 | 54 | return array; 55 | end 56 | 57 | Array.readFromQueue = function(queue, size) 58 | local array = {}; 59 | 60 | for i = 1, size do 61 | array[i] = queue.pop(); 62 | end 63 | 64 | return array; 65 | end 66 | 67 | Array.writeToQueue = function(queue, array) 68 | local size = Array.size(array); 69 | 70 | for i = 1, size do 71 | queue.push(array[i]); 72 | end 73 | end 74 | 75 | Array.toStream = function(array) 76 | local queue = Queue(); 77 | local i = 1; 78 | 79 | local byte = array[i]; 80 | while byte ~= nil do 81 | queue.push(byte); 82 | i = i + 1; 83 | byte = array[i]; 84 | end 85 | 86 | return queue.pop; 87 | end 88 | 89 | 90 | local fromHexTable = {}; 91 | for i = 0, 255 do 92 | fromHexTable[String.format("%02X", i)] = i; 93 | fromHexTable[String.format("%02x", i)] = i; 94 | end 95 | 96 | Array.fromHex = function(hex) 97 | local array = {}; 98 | 99 | for i = 1, String.len(hex) / 2 do 100 | local h = String.sub(hex, i * 2 - 1, i * 2); 101 | array[i] = fromHexTable[h]; 102 | end 103 | 104 | return array; 105 | end 106 | 107 | 108 | local toHexTable = {}; 109 | for i = 0, 255 do 110 | toHexTable[i] = String.format("%02X", i); 111 | end 112 | 113 | Array.toHex = function(array) 114 | local hex = {}; 115 | local i = 1; 116 | 117 | local byte = array[i]; 118 | while byte ~= nil do 119 | hex[i] = toHexTable[byte]; 120 | i = i + 1; 121 | byte = array[i]; 122 | end 123 | 124 | return table.concat(hex, ""); 125 | 126 | end 127 | 128 | Array.concat = function(a, b) 129 | local concat = {}; 130 | local out = 1; 131 | 132 | local i = 1; 133 | local byte = a[i]; 134 | while byte ~= nil do 135 | concat[out] = byte; 136 | i = i + 1; 137 | out = out + 1; 138 | byte = a[i]; 139 | end 140 | 141 | i = 1; 142 | byte = b[i]; 143 | while byte ~= nil do 144 | concat[out] = byte; 145 | i = i + 1; 146 | out = out + 1; 147 | byte = b[i]; 148 | end 149 | 150 | return concat; 151 | end 152 | 153 | Array.truncate = function(a, newSize) 154 | local x = {}; 155 | 156 | for i = 1, newSize do 157 | x[i] = a[i]; 158 | end 159 | 160 | return x; 161 | end 162 | 163 | Array.XOR = function(a, b) 164 | local x = {}; 165 | 166 | for k, v in pairs(a) do 167 | x[k] = XOR(v, b[k]); 168 | end 169 | 170 | return x; 171 | end 172 | 173 | Array.substitute = function(input, sbox) 174 | local out = {}; 175 | 176 | for k, v in pairs(input) do 177 | out[k] = sbox[v]; 178 | end 179 | 180 | return out; 181 | end 182 | 183 | Array.permute = function(input, pbox) 184 | local out = {}; 185 | 186 | for k, v in pairs(pbox) do 187 | out[k] = input[v]; 188 | end 189 | 190 | return out; 191 | end 192 | 193 | Array.copy = function(input) 194 | local out = {}; 195 | 196 | for k, v in pairs(input) do 197 | out[k] = v; 198 | end 199 | return out; 200 | end 201 | 202 | Array.slice = function(input, start, stop) 203 | local out = {}; 204 | 205 | if start == nil then 206 | start = 1 207 | elseif start < 0 then 208 | start = #input + start + 1 209 | end 210 | if stop == nil then 211 | stop = #input 212 | elseif stop < 0 then 213 | stop = #input + stop + 1 214 | end 215 | 216 | for i = start, stop do 217 | table.insert(out, input[i]) 218 | end 219 | 220 | return out; 221 | end 222 | 223 | return Array; 224 | -------------------------------------------------------------------------------- /lockbox/util/base64.lua: -------------------------------------------------------------------------------- 1 | local String = require("string"); 2 | local Bit = require("lockbox.util.bit"); 3 | 4 | local Stream = require("lockbox.util.stream"); 5 | 6 | local AND = Bit.band; 7 | local OR = Bit.bor; 8 | local NOT = Bit.bnot; 9 | local LSHIFT = Bit.lshift; 10 | local RSHIFT = Bit.rshift; 11 | 12 | 13 | local SYMBOLS = { 14 | [0]="A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", 15 | "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", 16 | "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", 17 | "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"}; 18 | 19 | local LOOKUP = {}; 20 | 21 | for k, v in pairs(SYMBOLS) do 22 | LOOKUP[k] = v; 23 | LOOKUP[v] = k; 24 | end 25 | 26 | 27 | local Base64 = {}; 28 | 29 | Base64.fromStream = function(stream) 30 | local bits = 0x00; 31 | local bitCount = 0; 32 | local base64 = {}; 33 | 34 | local byte = stream(); 35 | while byte ~= nil do 36 | bits = OR(LSHIFT(bits, 8), byte); 37 | bitCount = bitCount + 8; 38 | while bitCount >= 6 do 39 | bitCount = bitCount - 6; 40 | local temp = RSHIFT(bits, bitCount); 41 | table.insert(base64, LOOKUP[temp]); 42 | bits = AND(bits, NOT(LSHIFT(0xFFFFFFFF, bitCount))); 43 | end 44 | byte = stream(); 45 | end 46 | 47 | if (bitCount == 4) then 48 | bits = LSHIFT(bits, 2); 49 | table.insert(base64, LOOKUP[bits]); 50 | table.insert(base64, "="); 51 | elseif (bitCount == 2) then 52 | bits = LSHIFT(bits, 4); 53 | table.insert(base64, LOOKUP[bits]); 54 | table.insert(base64, "=="); 55 | end 56 | 57 | return table.concat(base64, ""); 58 | end 59 | 60 | Base64.fromArray = function(array) 61 | local ind = 0; 62 | 63 | local streamArray = function() 64 | ind = ind + 1; 65 | return array[ind]; 66 | end 67 | 68 | return Base64.fromStream(streamArray); 69 | end 70 | 71 | Base64.fromString = function(string) 72 | return Base64.fromStream(Stream.fromString(string)); 73 | end 74 | 75 | 76 | 77 | Base64.toStream = function(base64) 78 | local stream = coroutine.create(function() 79 | local bits = 0x00; 80 | local bitCount = 0; 81 | 82 | local yield = coroutine.yield; 83 | 84 | for c in String.gmatch(base64, ".") do 85 | if (c == "=") then 86 | bits = RSHIFT(bits, 2); bitCount = bitCount - 2; 87 | else 88 | bits = LSHIFT(bits, 6); bitCount = bitCount + 6; 89 | bits = OR(bits, LOOKUP[c]); 90 | end 91 | 92 | while(bitCount >= 8) do 93 | bitCount = bitCount - 8; 94 | local byte = RSHIFT(bits, bitCount); 95 | bits = AND(bits, NOT(LSHIFT(0xFFFFFFFF, bitCount))); 96 | yield(byte); 97 | end 98 | end 99 | end) 100 | 101 | local status = coroutine.status; 102 | 103 | return function() 104 | if status(stream) == 'dead' then return nil; end 105 | 106 | local _, byte = coroutine.resume(stream); 107 | return byte; 108 | end 109 | end 110 | 111 | Base64.toArray = function(base64) 112 | return Stream.toArray(Base64.toStream(base64)); 113 | end 114 | 115 | Base64.toString = function(base64) 116 | return Stream.toString(Base64.toStream(base64)); 117 | end 118 | 119 | return Base64; 120 | -------------------------------------------------------------------------------- /lockbox/util/bit.lua: -------------------------------------------------------------------------------- 1 | local ok, e 2 | ok = nil 3 | if not ok then 4 | ok, e = pcall(require, "bit") -- the LuaJIT one ? 5 | end 6 | if not ok then 7 | ok, e = pcall(require, "bit32") -- Lua 5.2 8 | end 9 | if not ok then 10 | ok, e = pcall(require, "bit.numberlua") -- for Lua 5.1, https://github.com/tst2005/lua-bit-numberlua/ 11 | end 12 | if not ok then 13 | error("no bitwise support found", 2) 14 | end 15 | assert(type(e) == "table", "invalid bit module") 16 | 17 | -- Workaround to support Lua 5.2 bit32 API with the LuaJIT bit one 18 | if e.rol and not e.lrotate then 19 | e.lrotate = e.rol 20 | end 21 | if e.ror and not e.rrotate then 22 | e.rrotate = e.ror 23 | end 24 | 25 | -- Workaround to support incomplete bit operations set 26 | if not e.ror and not e.rrotate then 27 | local ror = function(b, n) 28 | return e.bor(e.rshift(b, n), e.lshift(b, 32 - n)) 29 | end 30 | 31 | e.ror = ror 32 | e.rrotate = ror 33 | end 34 | 35 | if not e.rol and not e.lrotate then 36 | local rol = function(b, n) 37 | return e.bor(e.lshift(b, n), e.rshift(b, 32 - n)) 38 | end 39 | 40 | e.rol = rol 41 | e.lrotate = rol 42 | end 43 | 44 | return e 45 | -------------------------------------------------------------------------------- /lockbox/util/queue.lua: -------------------------------------------------------------------------------- 1 | local Queue = function() 2 | local queue = {}; 3 | local tail = 0; 4 | local head = 0; 5 | 6 | local public = {}; 7 | 8 | public.push = function(obj) 9 | queue[head] = obj; 10 | head = head + 1; 11 | return; 12 | end 13 | 14 | public.pop = function() 15 | if tail < head 16 | then 17 | local obj = queue[tail]; 18 | queue[tail] = nil; 19 | tail = tail + 1; 20 | return obj; 21 | else 22 | return nil; 23 | end 24 | end 25 | 26 | public.size = function() 27 | return head - tail; 28 | end 29 | 30 | public.getHead = function() 31 | return head; 32 | end 33 | 34 | public.getTail = function() 35 | return tail; 36 | end 37 | 38 | public.reset = function() 39 | queue = {}; 40 | head = 0; 41 | tail = 0; 42 | end 43 | 44 | return public; 45 | end 46 | 47 | return Queue; 48 | -------------------------------------------------------------------------------- /lockbox/util/stream.lua: -------------------------------------------------------------------------------- 1 | local Queue = require("lockbox.util.queue"); 2 | local String = require("string"); 3 | 4 | local Stream = {}; 5 | 6 | 7 | Stream.fromString = function(string) 8 | local i = 0; 9 | return function() 10 | i = i + 1; 11 | return String.byte(string, i); 12 | end 13 | end 14 | 15 | 16 | Stream.toString = function(stream) 17 | local array = {}; 18 | local i = 1; 19 | 20 | local byte = stream(); 21 | while byte ~= nil do 22 | array[i] = String.char(byte); 23 | i = i + 1; 24 | byte = stream(); 25 | end 26 | 27 | return table.concat(array); 28 | end 29 | 30 | 31 | Stream.fromArray = function(array) 32 | local queue = Queue(); 33 | local i = 1; 34 | 35 | local byte = array[i]; 36 | while byte ~= nil do 37 | queue.push(byte); 38 | i = i + 1; 39 | byte = array[i]; 40 | end 41 | 42 | return queue.pop; 43 | end 44 | 45 | 46 | Stream.toArray = function(stream) 47 | local array = {}; 48 | local i = 1; 49 | 50 | local byte = stream(); 51 | while byte ~= nil do 52 | array[i] = byte; 53 | i = i + 1; 54 | byte = stream(); 55 | end 56 | 57 | return array; 58 | end 59 | 60 | 61 | local fromHexTable = {}; 62 | for i = 0, 255 do 63 | fromHexTable[String.format("%02X", i)] = i; 64 | fromHexTable[String.format("%02x", i)] = i; 65 | end 66 | 67 | Stream.fromHex = function(hex) 68 | local queue = Queue(); 69 | 70 | for i = 1, String.len(hex) / 2 do 71 | local h = String.sub(hex, i * 2 - 1, i * 2); 72 | queue.push(fromHexTable[h]); 73 | end 74 | 75 | return queue.pop; 76 | end 77 | 78 | 79 | 80 | local toHexTable = {}; 81 | for i = 0, 255 do 82 | toHexTable[i] = String.format("%02X", i); 83 | end 84 | 85 | Stream.toHex = function(stream) 86 | local hex = {}; 87 | local i = 1; 88 | 89 | local byte = stream(); 90 | while byte ~= nil do 91 | hex[i] = toHexTable[byte]; 92 | i = i + 1; 93 | byte = stream(); 94 | end 95 | 96 | return table.concat(hex); 97 | end 98 | 99 | return Stream; 100 | -------------------------------------------------------------------------------- /rockspecs/lockbox-0.1.0-0.rockspec: -------------------------------------------------------------------------------- 1 | package = "lockbox" 2 | version = "0.1.0-0" 3 | source = { 4 | url = "git+https://github.com/somesocks/lua-lockbox.git", 5 | tag = "0.1.0" 6 | } 7 | description = { 8 | summary = "A collection of cryptographic primitives written in pure Lua", 9 | detailed = [[ 10 | A collection of cryptographic primitives and protocols written in pure Lua. This was written to provide cross-platform, tested reference implementations of many different cryptographic primitives. 11 | ]], 12 | homepage = "https://github.com/somesocks/lua-lockbox", 13 | maintainer = "James L.", 14 | license = "MIT/X11" 15 | } 16 | dependencies = { 17 | "lua >= 5.2" 18 | } 19 | build = { 20 | type = 'builtin', 21 | modules = { 22 | ['lockbox'] = 'lockbox/init.lua', 23 | ['lockbox.digest.sha2_224'] = 'lockbox/digest/sha2_224.lua', 24 | ['lockbox.digest.md4'] = 'lockbox/digest/md4.lua', 25 | ['lockbox.digest.ripemd160'] = 'lockbox/digest/ripemd160.lua', 26 | ['lockbox.digest.ripemd128'] = 'lockbox/digest/ripemd128.lua', 27 | ['lockbox.digest.md5'] = 'lockbox/digest/md5.lua', 28 | ['lockbox.digest.md2'] = 'lockbox/digest/md2.lua', 29 | ['lockbox.digest.sha1'] = 'lockbox/digest/sha1.lua', 30 | ['lockbox.digest.sha2_256'] = 'lockbox/digest/sha2_256.lua', 31 | ['lockbox.mac.hmac'] = 'lockbox/mac/hmac.lua', 32 | ['lockbox.padding.isoiec7816'] = 'lockbox/padding/isoiec7816.lua', 33 | ['lockbox.padding.pkcs7'] = 'lockbox/padding/pkcs7.lua', 34 | ['lockbox.padding.zero'] = 'lockbox/padding/zero.lua', 35 | ['lockbox.padding.ansix923'] = 'lockbox/padding/ansix923.lua', 36 | ['lockbox.kdf.pbkdf2'] = 'lockbox/kdf/pbkdf2.lua', 37 | ['lockbox.util.base64'] = 'lockbox/util/base64.lua', 38 | ['lockbox.util.array'] = 'lockbox/util/array.lua', 39 | ['lockbox.util.queue'] = 'lockbox/util/queue.lua', 40 | ['lockbox.util.bit'] = 'lockbox/util/bit.lua', 41 | ['lockbox.util.stream'] = 'lockbox/util/stream.lua', 42 | ['lockbox.cipher.mode.pcbc'] = 'lockbox/cipher/mode/pcbc.lua', 43 | ['lockbox.cipher.mode.ctr'] = 'lockbox/cipher/mode/ctr.lua', 44 | ['lockbox.cipher.mode.cbc'] = 'lockbox/cipher/mode/cbc.lua', 45 | ['lockbox.cipher.mode.cfb'] = 'lockbox/cipher/mode/cfb.lua', 46 | ['lockbox.cipher.mode.ofb'] = 'lockbox/cipher/mode/ofb.lua', 47 | ['lockbox.cipher.mode.ecb'] = 'lockbox/cipher/mode/ecb.lua', 48 | ['lockbox.cipher.mode.ige'] = 'lockbox/cipher/mode/ige.lua', 49 | ['lockbox.cipher.des'] = 'lockbox/cipher/des.lua', 50 | ['lockbox.cipher.aes192'] = 'lockbox/cipher/aes192.lua', 51 | ['lockbox.cipher.aes128'] = 'lockbox/cipher/aes128.lua', 52 | ['lockbox.cipher.des3'] = 'lockbox/cipher/des3.lua', 53 | ['lockbox.cipher.aes256'] = 'lockbox/cipher/aes256.lua' 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /rockspecs/lockbox-scm-0.rockspec: -------------------------------------------------------------------------------- 1 | package = "lockbox" 2 | version = "scm-0" 3 | 4 | source = { url = "git+https://github.com/somesocks/lua-lockbox.git" } 5 | 6 | description = { 7 | summary = "A collection of cryptographic primitives written in pure Lua", 8 | detailed = [[ 9 | A collection of cryptographic primitives and protocols written in pure Lua. This was written to provide cross-platform, tested reference implementations of many different cryptographic primitives. 10 | ]], 11 | homepage = "https://github.com/somesocks/lua-lockbox", 12 | maintainer = "James L.", 13 | license = "MIT/X11" 14 | } 15 | dependencies = { 16 | "lua >= 5.2" 17 | } 18 | build = { 19 | type = 'builtin', 20 | modules = { 21 | ['lockbox'] = 'lockbox/init.lua', 22 | ['lockbox.digest.sha2_224'] = 'lockbox/digest/sha2_224.lua', 23 | ['lockbox.digest.md4'] = 'lockbox/digest/md4.lua', 24 | ['lockbox.digest.ripemd160'] = 'lockbox/digest/ripemd160.lua', 25 | ['lockbox.digest.ripemd128'] = 'lockbox/digest/ripemd128.lua', 26 | ['lockbox.digest.md5'] = 'lockbox/digest/md5.lua', 27 | ['lockbox.digest.md2'] = 'lockbox/digest/md2.lua', 28 | ['lockbox.digest.sha1'] = 'lockbox/digest/sha1.lua', 29 | ['lockbox.digest.sha2_256'] = 'lockbox/digest/sha2_256.lua', 30 | ['lockbox.mac.hmac'] = 'lockbox/mac/hmac.lua', 31 | ['lockbox.padding.isoiec7816'] = 'lockbox/padding/isoiec7816.lua', 32 | ['lockbox.padding.pkcs7'] = 'lockbox/padding/pkcs7.lua', 33 | ['lockbox.padding.zero'] = 'lockbox/padding/zero.lua', 34 | ['lockbox.padding.ansix923'] = 'lockbox/padding/ansix923.lua', 35 | ['lockbox.kdf.hkdf'] = 'lockbox/kdf/hkdf.lua', 36 | ['lockbox.kdf.pbkdf2'] = 'lockbox/kdf/pbkdf2.lua', 37 | ['lockbox.util.base64'] = 'lockbox/util/base64.lua', 38 | ['lockbox.util.array'] = 'lockbox/util/array.lua', 39 | ['lockbox.util.queue'] = 'lockbox/util/queue.lua', 40 | ['lockbox.util.bit'] = 'lockbox/util/bit.lua', 41 | ['lockbox.util.stream'] = 'lockbox/util/stream.lua', 42 | ['lockbox.cipher.mode.pcbc'] = 'lockbox/cipher/mode/pcbc.lua', 43 | ['lockbox.cipher.mode.ctr'] = 'lockbox/cipher/mode/ctr.lua', 44 | ['lockbox.cipher.mode.cbc'] = 'lockbox/cipher/mode/cbc.lua', 45 | ['lockbox.cipher.mode.cfb'] = 'lockbox/cipher/mode/cfb.lua', 46 | ['lockbox.cipher.mode.ofb'] = 'lockbox/cipher/mode/ofb.lua', 47 | ['lockbox.cipher.mode.ecb'] = 'lockbox/cipher/mode/ecb.lua', 48 | ['lockbox.cipher.mode.ige'] = 'lockbox/cipher/mode/ige.lua', 49 | ['lockbox.cipher.des'] = 'lockbox/cipher/des.lua', 50 | ['lockbox.cipher.aes192'] = 'lockbox/cipher/aes192.lua', 51 | ['lockbox.cipher.aes128'] = 'lockbox/cipher/aes128.lua', 52 | ['lockbox.cipher.des3'] = 'lockbox/cipher/des3.lua', 53 | ['lockbox.cipher.aes256'] = 'lockbox/cipher/aes256.lua' 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /script/bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script ensures that lua interpreter is installed. 4 | # 5 | # Environment variables: 6 | # LUA_VERSION : Required version of the lua interpreter (e.g. lua-5.2, luajit-2). If this 7 | # version is not available on PATH and USE_SYSTEM_LUA != 'yes', then it will be 8 | # installed, otherwise it fails. 9 | # If not set, then the script checks if lua-5.2, lua-5.3, or luajit-2 is 10 | # available. If not and USE_SYSTEM_LUA != 'yes', then lua-5.1 will be installed, 11 | # otherwise it fails. 12 | # 13 | # USE_SYSTEM_LUA : Set to 'yes' if you want to use system provided lua. Default is to install 14 | # lua locally in .env directory. 15 | set -e 16 | 17 | DEFAULT_VERSION='lua-5.2' 18 | PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)" 19 | VENV_DIR="$PROJECT_DIR/.env" 20 | HEREROCKS_URI='https://raw.githubusercontent.com/mpeterv/hererocks/master/hererocks.py' 21 | 22 | 23 | #====================== Functions ======================# 24 | 25 | die() { 26 | echo -e "ERROR: $1" >&2 27 | exit ${2:-2} 28 | } 29 | 30 | exists() { 31 | command -v "$1" &>/dev/null 32 | } 33 | 34 | find-lua-exec() { 35 | local cmd; for cmd in lua luajit; do 36 | if exists "$cmd"; then 37 | command -v "$cmd" 38 | return 0 39 | fi 40 | done 41 | return 1 42 | } 43 | 44 | check-lua-version() { 45 | local luabin="$1" 46 | local ver="$($luabin -v 2>&1 | cut -d' ' -f1-2 | tr '[A-Z] ' '[a-z]-' || '')" 47 | 48 | if [ -n "$LUA_VERSION" ]; then 49 | [[ "$ver" == "$LUA_VERSION"* ]] 50 | else 51 | [[ "$ver" =~ ^lua-5.[23]|^luajit-2 ]] 52 | fi 53 | } 54 | 55 | install-lua() { 56 | local version=$1 57 | 58 | mkdir -p "$VENV_DIR" 59 | curl -o "$VENV_DIR/hererocks.py" "$HEREROCKS_URI" 60 | python "$VENV_DIR/hererocks.py" "$VENV_DIR" --luarocks=^ --${version/-/=} 61 | } 62 | 63 | 64 | #======================== Main =========================# 65 | 66 | cd "$PROJECT_DIR" 67 | 68 | if [[ "$USE_SYSTEM_LUA" == y* ]]; then 69 | 70 | if ! check-lua-version "$(find-lua-exec)"; then 71 | die "${LUA_VERSION:-lua 5.1-5.2 or luajit 2} is not installed and USE_SYSTEM_LUA=$USE_SYSTEM_LUA" 72 | 73 | elif ! exists luarocks; then 74 | die "luarocks is not installed and USE_SYSTEM_LUA=$USE_SYSTEM_LUA" 75 | fi 76 | 77 | else 78 | export PATH="$VENV_DIR/bin:$PATH" 79 | 80 | if ! check-lua-version "$VENV_DIR/bin/lua" || [ ! -x "$VENV_DIR/bin/luarocks" ]; then 81 | version="${LUA_VERSION:-$DEFAULT_VERSION}" 82 | 83 | echo "==> Installing $version and luarocks into $VENV_DIR..." >&2 84 | install-lua $version 85 | fi 86 | fi 87 | -------------------------------------------------------------------------------- /script/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Go to the project's root directory. 5 | cd "$(dirname "$0")/.." 6 | 7 | script/bootstrap 8 | 9 | echo -e '\n==> Running tests...' 10 | lua RunTests.lua 11 | 12 | echo -e '\n==> Running perf...' 13 | lua RunPerf.lua 14 | -------------------------------------------------------------------------------- /test/AES128CipherTests.lua: -------------------------------------------------------------------------------- 1 | local String = require("string"); 2 | 3 | local Array = require("lockbox.util.array"); 4 | local Stream = require("lockbox.util.stream"); 5 | 6 | local ECBMode = require("lockbox.cipher.mode.ecb"); 7 | local CBCMode = require("lockbox.cipher.mode.cbc"); 8 | local CFBMode = require("lockbox.cipher.mode.cfb"); 9 | local OFBMode = require("lockbox.cipher.mode.ofb"); 10 | local CTRMode = require("lockbox.cipher.mode.ctr"); 11 | local IGEMode = require("lockbox.cipher.mode.ige"); 12 | 13 | 14 | local ZeroPadding = require("lockbox.padding.zero"); 15 | 16 | local AES128Cipher = require("lockbox.cipher.aes128"); 17 | 18 | 19 | local testVectors = { 20 | { 21 | cipher = ECBMode.Cipher, 22 | decipher = ECBMode.Decipher, 23 | iv = Array.fromHex(""), 24 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 25 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 26 | ciphertext = Array.fromHex("3ad77bb40d7a3660a89ecaf32466ef97"), 27 | padding = ZeroPadding 28 | }, 29 | { 30 | cipher = ECBMode.Cipher, 31 | decipher = ECBMode.Decipher, 32 | iv = Array.fromHex(""), 33 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 34 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 35 | ciphertext = Array.fromHex("f5d3d58503b9699de785895a96fdbaaf"), 36 | padding = ZeroPadding 37 | }, 38 | { 39 | cipher = ECBMode.Cipher, 40 | decipher = ECBMode.Decipher, 41 | iv = Array.fromHex(""), 42 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 43 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 44 | ciphertext = Array.fromHex("43b1cd7f598ece23881b00e3ed030688"), 45 | padding = ZeroPadding 46 | }, 47 | { 48 | cipher = ECBMode.Cipher, 49 | decipher = ECBMode.Decipher, 50 | iv = Array.fromHex(""), 51 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 52 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 53 | ciphertext = Array.fromHex("7b0c785e27e8ad3f8223207104725dd4"), 54 | padding = ZeroPadding 55 | }, 56 | 57 | 58 | { 59 | cipher = CBCMode.Cipher, 60 | decipher = CBCMode.Decipher, 61 | iv = Array.fromHex("000102030405060708090A0B0C0D0E0F"), 62 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 63 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 64 | ciphertext = Array.fromHex("7649abac8119b246cee98e9b12e9197d"), 65 | padding = ZeroPadding 66 | }, 67 | { 68 | cipher = CBCMode.Cipher, 69 | decipher = CBCMode.Decipher, 70 | iv = Array.fromHex("7649ABAC8119B246CEE98E9B12E9197D"), 71 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 72 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 73 | ciphertext = Array.fromHex("5086cb9b507219ee95db113a917678b2"), 74 | padding = ZeroPadding 75 | }, 76 | { 77 | cipher = CBCMode.Cipher, 78 | decipher = CBCMode.Decipher, 79 | iv = Array.fromHex("5086CB9B507219EE95DB113A917678B2"), 80 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 81 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 82 | ciphertext = Array.fromHex("73bed6b8e3c1743b7116e69e22229516"), 83 | padding = ZeroPadding 84 | }, 85 | { 86 | cipher = CBCMode.Cipher, 87 | decipher = CBCMode.Decipher, 88 | iv = Array.fromHex("73BED6B8E3C1743B7116E69E22229516"), 89 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 90 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 91 | ciphertext = Array.fromHex("3ff1caa1681fac09120eca307586e1a7"), 92 | padding = ZeroPadding 93 | }, 94 | 95 | 96 | { 97 | cipher = CFBMode.Cipher, 98 | decipher = CFBMode.Decipher, 99 | iv = Array.fromHex("000102030405060708090a0b0c0d0e0f"), 100 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 101 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 102 | ciphertext = Array.fromHex("3b3fd92eb72dad20333449f8e83cfb4a"), 103 | padding = ZeroPadding 104 | }, 105 | { 106 | cipher = CFBMode.Cipher, 107 | decipher = CFBMode.Decipher, 108 | iv = Array.fromHex("3B3FD92EB72DAD20333449F8E83CFB4A"), 109 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 110 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 111 | ciphertext = Array.fromHex("c8a64537a0b3a93fcde3cdad9f1ce58b"), 112 | padding = ZeroPadding 113 | }, 114 | { 115 | cipher = CFBMode.Cipher, 116 | decipher = CFBMode.Decipher, 117 | iv = Array.fromHex("C8A64537A0B3A93FCDE3CDAD9F1CE58B"), 118 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 119 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 120 | ciphertext = Array.fromHex("26751f67a3cbb140b1808cf187a4f4df"), 121 | padding = ZeroPadding 122 | }, 123 | { 124 | cipher = CFBMode.Cipher, 125 | decipher = CFBMode.Decipher, 126 | iv = Array.fromHex("26751F67A3CBB140B1808CF187A4F4DF"), 127 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 128 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 129 | ciphertext = Array.fromHex("c04b05357c5d1c0eeac4c66f9ff7f2e6"), 130 | padding = ZeroPadding 131 | }, 132 | 133 | { 134 | cipher = OFBMode.Cipher, 135 | decipher = OFBMode.Decipher, 136 | iv = Array.fromHex("000102030405060708090A0B0C0D0E0F"), 137 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 138 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 139 | ciphertext = Array.fromHex("3b3fd92eb72dad20333449f8e83cfb4a"), 140 | padding = ZeroPadding 141 | }, 142 | { 143 | cipher = OFBMode.Cipher, 144 | decipher = OFBMode.Decipher, 145 | iv = Array.fromHex("50FE67CC996D32B6DA0937E99BAFEC60"), 146 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 147 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 148 | ciphertext = Array.fromHex("7789508d16918f03f53c52dac54ed825"), 149 | padding = ZeroPadding 150 | }, 151 | { 152 | cipher = OFBMode.Cipher, 153 | decipher = OFBMode.Decipher, 154 | iv = Array.fromHex("D9A4DADA0892239F6B8B3D7680E15674"), 155 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 156 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 157 | ciphertext = Array.fromHex("9740051e9c5fecf64344f7a82260edcc"), 158 | padding = ZeroPadding 159 | }, 160 | { 161 | cipher = OFBMode.Cipher, 162 | decipher = OFBMode.Decipher, 163 | iv = Array.fromHex("A78819583F0308E7A6BF36B1386ABF23"), 164 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 165 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 166 | ciphertext = Array.fromHex("304c6528f659c77866a510d9c1d6ae5e"), 167 | padding = ZeroPadding 168 | }, 169 | 170 | { 171 | cipher = CTRMode.Cipher, 172 | decipher = CTRMode.Decipher, 173 | iv = Array.fromHex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 174 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 175 | plaintext = Array.fromHex( 176 | "6bc1bee22e409f96e93d7e117393172a" 177 | .."ae2d8a571e03ac9c9eb76fac45af8e51" 178 | .."30c81c46a35ce411e5fbc1191a0a52ef" 179 | .."f69f2445df4f9b17ad2b417be66c3710"), 180 | ciphertext = Array.fromHex( 181 | "874d6191b620e3261bef6864990db6ce" 182 | .."9806f66b7970fdff8617187bb9fffdff" 183 | .."5ae4df3edbd5d35e5b4f09020db03eab" 184 | .."1e031dda2fbe03d1792170a0f3009cee"), 185 | padding = ZeroPadding 186 | }, 187 | { 188 | cipher = CTRMode.Cipher, 189 | decipher = CTRMode.Decipher, 190 | iv = Array.fromHex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 191 | key = Array.fromHex("2b7e151628aed2a6abf7158809cf4f3c"), 192 | ciphertext = Array.fromHex( 193 | "874d6191b620e3261bef6864990db6ce" 194 | .."9806f66b7970fdff8617187bb9fffdff" 195 | .."5ae4df3edbd5d35e5b4f09020db03eab" 196 | .."1e031dda2fbe03d1792170a0f3009cee"), 197 | plaintext = Array.fromHex( 198 | "6bc1bee22e409f96e93d7e117393172a" 199 | .."ae2d8a571e03ac9c9eb76fac45af8e51" 200 | .."30c81c46a35ce411e5fbc1191a0a52ef" 201 | .."f69f2445df4f9b17ad2b417be66c3710"), 202 | padding = ZeroPadding 203 | }, 204 | 205 | { 206 | cipher = IGEMode.Cipher, 207 | decipher = IGEMode.Decipher, 208 | iv = Array.fromHex("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"), 209 | key = Array.fromHex("000102030405060708090A0B0C0D0E0F"), 210 | plaintext = Array.fromHex("0000000000000000000000000000000000000000000000000000000000000000"), 211 | ciphertext = Array.fromHex("1A8519A6557BE652E9DA8E43DA4EF4453CF456B4CA488AA383C79C98B34797CB"), 212 | padding = ZeroPadding 213 | }, 214 | 215 | { 216 | cipher = IGEMode.Cipher, 217 | decipher = IGEMode.Decipher, 218 | iv = Array.fromHex("6D656E746174696F6E206F6620494745206D6F646520666F72204F70656E5353"), 219 | key = Array.fromHex("5468697320697320616E20696D706C65"), 220 | plaintext = Array.fromHex("99706487A1CDE613BC6DE0B6F24B1C7AA448C8B9C3403E3467A8CAD89340F53B"), 221 | ciphertext = Array.fromHex("4C2E204C6574277320686F70652042656E20676F74206974207269676874210A"), 222 | padding = ZeroPadding 223 | }, 224 | 225 | 226 | }; 227 | 228 | for _, v in pairs(testVectors) do 229 | local cipher = v.cipher() 230 | .setKey(v.key) 231 | .setBlockCipher(AES128Cipher) 232 | .setPadding(v.padding); 233 | 234 | local cipherOutput = cipher 235 | .init() 236 | .update(Stream.fromArray(v.iv)) 237 | .update(Stream.fromArray(v.plaintext)) 238 | .finish() 239 | .asHex(); 240 | 241 | local decipher = v.decipher() 242 | .setKey(v.key) 243 | .setBlockCipher(AES128Cipher) 244 | .setPadding(v.padding); 245 | 246 | local plainOutput = decipher 247 | .init() 248 | .update(Stream.fromArray(v.iv)) 249 | .update(Stream.fromArray(v.ciphertext)) 250 | .finish() 251 | .asHex(); 252 | 253 | assert(cipherOutput == Array.toHex(v.ciphertext) 254 | , String.format("cipher failed! expected(%s) got(%s)", Array.toHex(v.ciphertext), cipherOutput)); 255 | 256 | assert(plainOutput == Array.toHex(v.plaintext) 257 | , String.format("decipher failed! expected(%s) got(%s)", Array.toHex(v.plaintext), plainOutput)); 258 | 259 | end 260 | -------------------------------------------------------------------------------- /test/AES192CipherTests.lua: -------------------------------------------------------------------------------- 1 | local String = require("string"); 2 | 3 | local Array = require("lockbox.util.array"); 4 | local Stream = require("lockbox.util.stream"); 5 | 6 | local ECBMode = require("lockbox.cipher.mode.ecb"); 7 | local CBCMode = require("lockbox.cipher.mode.cbc"); 8 | local CFBMode = require("lockbox.cipher.mode.cfb"); 9 | local OFBMode = require("lockbox.cipher.mode.ofb"); 10 | local CTRMode = require("lockbox.cipher.mode.ctr"); 11 | 12 | local ZeroPadding = require("lockbox.padding.zero"); 13 | 14 | local AES192Cipher = require("lockbox.cipher.aes192"); 15 | 16 | 17 | local testVectors = { 18 | { 19 | cipher = ECBMode.Cipher, 20 | decipher = ECBMode.Decipher, 21 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 22 | iv = Array.fromHex(""), 23 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 24 | ciphertext = Array.fromHex("bd334f1d6e45f25ff712a214571fa5cc"), 25 | padding = ZeroPadding 26 | }, 27 | { 28 | cipher = ECBMode.Cipher, 29 | decipher = ECBMode.Decipher, 30 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 31 | iv = Array.fromHex(""), 32 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 33 | ciphertext = Array.fromHex("974104846d0ad3ad7734ecb3ecee4eef"), 34 | padding = ZeroPadding 35 | }, 36 | { 37 | cipher = ECBMode.Cipher, 38 | decipher = ECBMode.Decipher, 39 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 40 | iv = Array.fromHex(""), 41 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 42 | ciphertext = Array.fromHex("ef7afd2270e2e60adce0ba2face6444e"), 43 | padding = ZeroPadding 44 | }, 45 | { 46 | cipher = ECBMode.Cipher, 47 | decipher = ECBMode.Decipher, 48 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 49 | iv = Array.fromHex(""), 50 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 51 | ciphertext = Array.fromHex("9a4b41ba738d6c72fb16691603c18e0e"), 52 | padding = ZeroPadding 53 | }, 54 | 55 | 56 | { 57 | cipher = CBCMode.Cipher, 58 | decipher = CBCMode.Decipher, 59 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 60 | iv = Array.fromHex("000102030405060708090A0B0C0D0E0F"), 61 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 62 | ciphertext = Array.fromHex("4f021db243bc633d7178183a9fa071e8"), 63 | padding = ZeroPadding 64 | }, 65 | { 66 | cipher = CBCMode.Cipher, 67 | decipher = CBCMode.Decipher, 68 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 69 | iv = Array.fromHex("4F021DB243BC633D7178183A9FA071E8"), 70 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 71 | ciphertext = Array.fromHex("b4d9ada9ad7dedf4e5e738763f69145a"), 72 | padding = ZeroPadding 73 | }, 74 | { 75 | cipher = CBCMode.Cipher, 76 | decipher = CBCMode.Decipher, 77 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 78 | iv = Array.fromHex("B4D9ADA9AD7DEDF4E5E738763F69145A"), 79 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 80 | ciphertext = Array.fromHex("571b242012fb7ae07fa9baac3df102e0"), 81 | padding = ZeroPadding 82 | }, 83 | { 84 | cipher = CBCMode.Cipher, 85 | decipher = CBCMode.Decipher, 86 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 87 | iv = Array.fromHex("571B242012FB7AE07FA9BAAC3DF102E0"), 88 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 89 | ciphertext = Array.fromHex("08b0e27988598881d920a9e64f5615cd"), 90 | padding = ZeroPadding 91 | }, 92 | 93 | 94 | { 95 | cipher = CFBMode.Cipher, 96 | decipher = CFBMode.Decipher, 97 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 98 | iv = Array.fromHex("000102030405060708090A0B0C0D0E0F"), 99 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 100 | ciphertext = Array.fromHex("cdc80d6fddf18cab34c25909c99a4174"), 101 | padding = ZeroPadding 102 | }, 103 | { 104 | cipher = CFBMode.Cipher, 105 | decipher = CFBMode.Decipher, 106 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 107 | iv = Array.fromHex("CDC80D6FDDF18CAB34C25909C99A4174"), 108 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 109 | ciphertext = Array.fromHex("67ce7f7f81173621961a2b70171d3d7a"), 110 | padding = ZeroPadding 111 | }, 112 | { 113 | cipher = CFBMode.Cipher, 114 | decipher = CFBMode.Decipher, 115 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 116 | iv = Array.fromHex("67CE7F7F81173621961A2B70171D3D7A"), 117 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 118 | ciphertext = Array.fromHex("2e1e8a1dd59b88b1c8e60fed1efac4c9"), 119 | padding = ZeroPadding 120 | }, 121 | { 122 | cipher = CFBMode.Cipher, 123 | decipher = CFBMode.Decipher, 124 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 125 | iv = Array.fromHex("2E1E8A1DD59B88B1C8E60FED1EFAC4C9"), 126 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 127 | ciphertext = Array.fromHex("c05f9f9ca9834fa042ae8fba584b09ff"), 128 | padding = ZeroPadding 129 | }, 130 | 131 | 132 | { 133 | cipher = OFBMode.Cipher, 134 | decipher = OFBMode.Decipher, 135 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 136 | iv = Array.fromHex("000102030405060708090A0B0C0D0E0F"), 137 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 138 | ciphertext = Array.fromHex("cdc80d6fddf18cab34c25909c99a4174"), 139 | padding = ZeroPadding 140 | }, 141 | { 142 | cipher = OFBMode.Cipher, 143 | decipher = OFBMode.Decipher, 144 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 145 | iv = Array.fromHex("A609B38DF3B1133DDDFF2718BA09565E"), 146 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 147 | ciphertext = Array.fromHex("fcc28b8d4c63837c09e81700c1100401"), 148 | padding = ZeroPadding 149 | }, 150 | { 151 | cipher = OFBMode.Cipher, 152 | decipher = OFBMode.Decipher, 153 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 154 | iv = Array.fromHex("52EF01DA52602FE0975F78AC84BF8A50"), 155 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 156 | ciphertext = Array.fromHex("8d9a9aeac0f6596f559c6d4daf59a5f2"), 157 | padding = ZeroPadding 158 | }, 159 | { 160 | cipher = OFBMode.Cipher, 161 | decipher = OFBMode.Decipher, 162 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 163 | iv = Array.fromHex("BD5286AC63AABD7EB067AC54B553F71D"), 164 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 165 | ciphertext = Array.fromHex("6d9f200857ca6c3e9cac524bd9acc92a"), 166 | padding = ZeroPadding 167 | }, 168 | 169 | { 170 | cipher = CTRMode.Cipher, 171 | decipher = CTRMode.Decipher, 172 | key = Array.fromHex("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), 173 | iv = Array.fromHex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 174 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45a" .. 175 | "f8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"), 176 | ciphertext = Array.fromHex("1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4" .. 177 | "ce8e941e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050"), 178 | padding = ZeroPadding 179 | }, 180 | 181 | 182 | }; 183 | 184 | for _, v in pairs(testVectors) do 185 | local cipher = v.cipher() 186 | .setKey(v.key) 187 | .setBlockCipher(AES192Cipher) 188 | .setPadding(v.padding); 189 | 190 | local cipherOutput = cipher 191 | .init() 192 | .update(Stream.fromArray(v.iv)) 193 | .update(Stream.fromArray(v.plaintext)) 194 | .finish() 195 | .asHex(); 196 | 197 | local decipher = v.decipher() 198 | .setKey(v.key) 199 | .setBlockCipher(AES192Cipher) 200 | .setPadding(v.padding); 201 | 202 | local plainOutput = decipher 203 | .init() 204 | .update(Stream.fromArray(v.iv)) 205 | .update(Stream.fromHex(cipherOutput)) 206 | .finish() 207 | .asHex(); 208 | 209 | assert(cipherOutput == Array.toHex(v.ciphertext) 210 | , String.format("cipher failed! expected(%s) got(%s)", Array.toHex(v.ciphertext), cipherOutput)); 211 | 212 | assert(plainOutput == Array.toHex(v.plaintext) 213 | , String.format("decipher failed! expected(%s) got(%s)", Array.toHex(v.plaintext), plainOutput)); 214 | 215 | end 216 | -------------------------------------------------------------------------------- /test/AES256CipherTests.lua: -------------------------------------------------------------------------------- 1 | local String = require("string"); 2 | 3 | local Array = require("lockbox.util.array"); 4 | local Stream = require("lockbox.util.stream"); 5 | 6 | local ECBMode = require("lockbox.cipher.mode.ecb"); 7 | local CBCMode = require("lockbox.cipher.mode.cbc"); 8 | local CFBMode = require("lockbox.cipher.mode.cfb"); 9 | local OFBMode = require("lockbox.cipher.mode.ofb"); 10 | local CTRMode = require("lockbox.cipher.mode.ctr"); 11 | 12 | local ZeroPadding = require("lockbox.padding.zero"); 13 | 14 | local AES256Cipher = require("lockbox.cipher.aes256"); 15 | 16 | 17 | local testVectors = { 18 | { 19 | cipher = ECBMode.Cipher, 20 | decipher = ECBMode.Decipher, 21 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 22 | iv = Array.fromHex(""), 23 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 24 | ciphertext = Array.fromHex("f3eed1bdb5d2a03c064b5a7e3db181f8"), 25 | padding = ZeroPadding 26 | }, 27 | { 28 | cipher = ECBMode.Cipher, 29 | decipher = ECBMode.Decipher, 30 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 31 | iv = Array.fromHex(""), 32 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 33 | ciphertext = Array.fromHex("591ccb10d410ed26dc5ba74a31362870"), 34 | padding = ZeroPadding 35 | }, 36 | { 37 | cipher = ECBMode.Cipher, 38 | decipher = ECBMode.Decipher, 39 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 40 | iv = Array.fromHex(""), 41 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 42 | ciphertext = Array.fromHex("b6ed21b99ca6f4f9f153e7b1beafed1d"), 43 | padding = ZeroPadding 44 | }, 45 | { 46 | cipher = ECBMode.Cipher, 47 | decipher = ECBMode.Decipher, 48 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 49 | iv = Array.fromHex(""), 50 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 51 | ciphertext = Array.fromHex("23304b7a39f9f3ff067d8d8f9e24ecc7"), 52 | padding = ZeroPadding 53 | }, 54 | 55 | 56 | { 57 | cipher = CBCMode.Cipher, 58 | decipher = CBCMode.Decipher, 59 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 60 | iv = Array.fromHex("000102030405060708090A0B0C0D0E0F"), 61 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 62 | ciphertext = Array.fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd6"), 63 | padding = ZeroPadding 64 | }, 65 | { 66 | cipher = CBCMode.Cipher, 67 | decipher = CBCMode.Decipher, 68 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 69 | iv = Array.fromHex("F58C4C04D6E5F1BA779EABFB5F7BFBD6"), 70 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 71 | ciphertext = Array.fromHex("9cfc4e967edb808d679f777bc6702c7d"), 72 | padding = ZeroPadding 73 | }, 74 | { 75 | cipher = CBCMode.Cipher, 76 | decipher = CBCMode.Decipher, 77 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 78 | iv = Array.fromHex("9CFC4E967EDB808D679F777BC6702C7D"), 79 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 80 | ciphertext = Array.fromHex("39f23369a9d9bacfa530e26304231461"), 81 | padding = ZeroPadding 82 | }, 83 | { 84 | cipher = CBCMode.Cipher, 85 | decipher = CBCMode.Decipher, 86 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 87 | iv = Array.fromHex("39F23369A9D9BACFA530E26304231461"), 88 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 89 | ciphertext = Array.fromHex("b2eb05e2c39be9fcda6c19078c6a9d1b"), 90 | padding = ZeroPadding 91 | }, 92 | 93 | 94 | { 95 | cipher = CFBMode.Cipher, 96 | decipher = CFBMode.Decipher, 97 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 98 | iv = Array.fromHex("000102030405060708090A0B0C0D0E0F"), 99 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 100 | ciphertext = Array.fromHex("DC7E84BFDA79164B7ECD8486985D3860"), 101 | padding = ZeroPadding 102 | }, 103 | { 104 | cipher = CFBMode.Cipher, 105 | decipher = CFBMode.Decipher, 106 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 107 | iv = Array.fromHex("DC7E84BFDA79164B7ECD8486985D3860"), 108 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 109 | ciphertext = Array.fromHex("39ffed143b28b1c832113c6331e5407b"), 110 | padding = ZeroPadding 111 | }, 112 | { 113 | cipher = CFBMode.Cipher, 114 | decipher = CFBMode.Decipher, 115 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 116 | iv = Array.fromHex("39FFED143B28B1C832113C6331E5407B"), 117 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 118 | ciphertext = Array.fromHex("df10132415e54b92a13ed0a8267ae2f9"), 119 | padding = ZeroPadding 120 | }, 121 | { 122 | cipher = CFBMode.Cipher, 123 | decipher = CFBMode.Decipher, 124 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 125 | iv = Array.fromHex("DF10132415E54B92A13ED0A8267AE2F9"), 126 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 127 | ciphertext = Array.fromHex("75a385741ab9cef82031623d55b1e471"), 128 | padding = ZeroPadding 129 | }, 130 | 131 | 132 | { 133 | cipher = OFBMode.Cipher, 134 | decipher = OFBMode.Decipher, 135 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 136 | iv = Array.fromHex("000102030405060708090A0B0C0D0E0F"), 137 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172a"), 138 | ciphertext = Array.fromHex("dc7e84bfda79164b7ecd8486985d3860"), 139 | padding = ZeroPadding 140 | }, 141 | { 142 | cipher = OFBMode.Cipher, 143 | decipher = OFBMode.Decipher, 144 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 145 | iv = Array.fromHex("B7BF3A5DF43989DD97F0FA97EBCE2F4A"), 146 | plaintext = Array.fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"), 147 | ciphertext = Array.fromHex("4febdc6740d20b3ac88f6ad82a4fb08d"), 148 | padding = ZeroPadding 149 | }, 150 | { 151 | cipher = OFBMode.Cipher, 152 | decipher = OFBMode.Decipher, 153 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 154 | iv = Array.fromHex("E1C656305ED1A7A6563805746FE03EDC"), 155 | plaintext = Array.fromHex("30c81c46a35ce411e5fbc1191a0a52ef"), 156 | ciphertext = Array.fromHex("71ab47a086e86eedf39d1c5bba97c408"), 157 | padding = ZeroPadding 158 | }, 159 | { 160 | cipher = OFBMode.Cipher, 161 | decipher = OFBMode.Decipher, 162 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 163 | iv = Array.fromHex("41635BE625B48AFC1666DD42A09D96E7"), 164 | plaintext = Array.fromHex("f69f2445df4f9b17ad2b417be66c3710"), 165 | ciphertext = Array.fromHex("0126141d67f37be8538f5a8be740e484"), 166 | padding = ZeroPadding 167 | }, 168 | 169 | { 170 | cipher = CTRMode.Cipher, 171 | decipher = CTRMode.Decipher, 172 | key = Array.fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), 173 | iv = Array.fromHex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 174 | plaintext = Array.fromHex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45" .. 175 | "af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"), 176 | ciphertext = Array.fromHex("601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c52b0930" .. 177 | "daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6"), 178 | padding = ZeroPadding 179 | }, 180 | 181 | 182 | }; 183 | 184 | for _, v in pairs(testVectors) do 185 | local cipher = v.cipher() 186 | .setKey(v.key) 187 | .setBlockCipher(AES256Cipher) 188 | .setPadding(v.padding); 189 | 190 | local cipherOutput = cipher 191 | .init() 192 | .update(Stream.fromArray(v.iv)) 193 | .update(Stream.fromArray(v.plaintext)) 194 | .finish() 195 | .asHex(); 196 | 197 | local decipher = v.decipher() 198 | .setKey(v.key) 199 | .setBlockCipher(AES256Cipher) 200 | .setPadding(v.padding); 201 | 202 | local plainOutput = decipher 203 | .init() 204 | .update(Stream.fromArray(v.iv)) 205 | .update(Stream.fromHex(cipherOutput)) 206 | .finish() 207 | .asHex(); 208 | 209 | assert(cipherOutput == Array.toHex(v.ciphertext) 210 | , String.format("cipher failed! expected(%s) got(%s)", Array.toHex(v.ciphertext), cipherOutput)); 211 | 212 | assert(plainOutput == Array.toHex(v.plaintext) 213 | , String.format("decipher failed! expected(%s) got(%s)", Array.toHex(v.plaintext), plainOutput)); 214 | 215 | end 216 | -------------------------------------------------------------------------------- /test/Base64Tests.lua: -------------------------------------------------------------------------------- 1 | local String = require("string"); 2 | local Array = require("lockbox.util.array"); 3 | local Stream = require("lockbox.util.stream"); 4 | local Base64 = require("lockbox.util.base64"); 5 | 6 | local test_vectors = { 7 | { 8 | plain = "foobar", 9 | enc = "Zm9vYmFy" 10 | }, 11 | { 12 | plain = "fooba", 13 | enc = "Zm9vYmE=" 14 | }, 15 | { 16 | plain = "foob", 17 | enc = "Zm9vYg==" 18 | }, 19 | { 20 | plain = "foo", 21 | enc = "Zm9v" 22 | }, 23 | { 24 | plain = "fo", 25 | enc = "Zm8=" 26 | }, 27 | { 28 | plain = "f", 29 | enc = "Zg==" 30 | }, 31 | { 32 | plain = "", 33 | enc = "" 34 | }, 35 | 36 | 37 | }; 38 | 39 | for _, v in pairs(test_vectors) do 40 | local out 41 | out = Base64.fromStream(Stream.fromString(v.plain)); 42 | assert(out == v.enc, String.format("STREAM ENCODING FAILED expected(%s) actual(%s)", v.enc, out)); 43 | 44 | out = Base64.fromArray(Array.fromString(v.plain)); 45 | assert(out == v.enc, String.format("STREAM ENCODING FAILED expected(%s) actual(%s)", v.enc, out)); 46 | 47 | out = Base64.fromString(v.plain); 48 | assert(out == v.enc, String.format("ARRAY ENECODING FAILED expected(%s) actual(%s)", v.enc, out)); 49 | 50 | out = Base64.toStream(v.enc); 51 | out = Stream.toString(out); 52 | assert(out == v.plain, String.format("ARRAY DECODING FAILED expected(%s) actual(%s)", v.plain, out)); 53 | 54 | out = Base64.toArray(v.enc); 55 | out = Array.toString(out); 56 | assert(out == v.plain, String.format("ARRAY DECODING FAILED expected(%s) actual(%s)", v.plain, out)); 57 | 58 | out = Base64.toString(v.enc); 59 | assert(out == v.plain, String.format("ARRAY DECODING FAILED expected(%s) actual(%s)", v.plain, out)); 60 | 61 | end 62 | -------------------------------------------------------------------------------- /test/DES3CipherTests.lua: -------------------------------------------------------------------------------- 1 | local String = require("string"); 2 | 3 | local Array = require("lockbox.util.array"); 4 | local Stream = require("lockbox.util.stream"); 5 | 6 | local ECBMode = require("lockbox.cipher.mode.ecb"); 7 | 8 | local CBCMode = require("lockbox.cipher.mode.cbc"); 9 | 10 | local PKCS7Padding = require("lockbox.padding.pkcs7"); 11 | local ZeroPadding = require("lockbox.padding.zero"); 12 | 13 | local DES3Cipher = require("lockbox.cipher.des3"); 14 | 15 | local testVectors = { 16 | { 17 | mode = ECBMode, 18 | key = Array.fromHex("8000000000000000"), 19 | iv = Array.fromString(""), 20 | plaintext = Array.fromHex("0000000000000000"), 21 | ciphertext= Array.fromHex("95A8D72813DAA94D"), 22 | padding = ZeroPadding 23 | }, 24 | { 25 | mode = ECBMode, 26 | key = Array.fromHex("4000000000000000"), 27 | iv = Array.fromString(""), 28 | plaintext = Array.fromHex("0000000000000000"), 29 | ciphertext = Array.fromHex("0EEC1487DD8C26D5"), 30 | padding = ZeroPadding 31 | }, 32 | { 33 | mode = ECBMode, 34 | key = Array.fromHex("2000000000000000"), 35 | iv = Array.fromString(""), 36 | plaintext = Array.fromHex("0000000000000000"), 37 | ciphertext = Array.fromHex("7AD16FFB79C45926"), 38 | padding = ZeroPadding 39 | }, 40 | { 41 | mode = ECBMode, 42 | key = Array.fromHex("1000000000000000"), 43 | iv = Array.fromString(""), 44 | plaintext = Array.fromHex("0000000000000000"), 45 | ciphertext = Array.fromHex("D3746294CA6A6CF3"), 46 | padding = ZeroPadding 47 | }, 48 | { 49 | mode = ECBMode, 50 | key = Array.fromHex("0800000000000000"), 51 | iv = Array.fromString(""), 52 | plaintext = Array.fromHex("0000000000000000"), 53 | ciphertext = Array.fromHex("809F5F873C1FD761"), 54 | padding = ZeroPadding 55 | }, 56 | { 57 | mode = ECBMode, 58 | key = Array.fromHex("0400000000000000"), 59 | iv = Array.fromString(""), 60 | plaintext = Array.fromHex("0000000000000000"), 61 | ciphertext = Array.fromHex("C02FAFFEC989D1FC"), 62 | padding = ZeroPadding 63 | }, 64 | { 65 | mode = ECBMode, 66 | key = Array.fromHex("0200000000000000"), 67 | iv = Array.fromString(""), 68 | plaintext = Array.fromHex("0000000000000000"), 69 | ciphertext = Array.fromHex("4615AA1D33E72F10"), 70 | padding = ZeroPadding 71 | }, 72 | { 73 | mode = ECBMode, 74 | key = Array.fromHex("0100000000000000"), 75 | iv = Array.fromString(""), 76 | plaintext = Array.fromHex("0000000000000000"), 77 | ciphertext = Array.fromHex("8CA64DE9C1B123A7"), 78 | padding = ZeroPadding 79 | }, 80 | 81 | { 82 | mode = CBCMode, 83 | key = Array.fromString("12345678"), 84 | iv = Array.fromString("abcdefgh"), 85 | plaintext = Array.fromString("This is the message to encrypt!!"), 86 | ciphertext = Array.fromHex("6CA9470C849D1CC1A59FFC148F1CB5E9CF1F5C0328A7E8756387FF4D0FE46050"), 87 | padding = PKCS7Padding 88 | }, 89 | 90 | 91 | { 92 | mode = ECBMode, 93 | key = Array.fromHex("80000000000000000000000000000000"), 94 | iv = Array.fromString(""), 95 | plaintext = Array.fromHex("0000000000000000"), 96 | ciphertext = Array.fromHex("FAFD5084374FCE34"), 97 | padding = ZeroPadding 98 | }, 99 | { 100 | mode = ECBMode, 101 | key = Array.fromHex("40000000000000000000000000000000"), 102 | iv = Array.fromString(""), 103 | plaintext = Array.fromHex("0000000000000000"), 104 | ciphertext = Array.fromHex("60CC37B7B537A1DC"), 105 | padding = ZeroPadding 106 | }, 107 | { 108 | mode = ECBMode, 109 | key = Array.fromHex("20000000000000000000000000000000"), 110 | iv = Array.fromString(""), 111 | plaintext = Array.fromHex("0000000000000000"), 112 | ciphertext = Array.fromHex("BE3E7304FE92C2BC"), 113 | padding = ZeroPadding 114 | }, 115 | { 116 | mode = ECBMode, 117 | key = Array.fromHex("10000000000000000000000000000000"), 118 | iv = Array.fromString(""), 119 | plaintext = Array.fromHex("0000000000000000"), 120 | ciphertext = Array.fromHex("49F9E7A60C406DBF"), 121 | padding = ZeroPadding 122 | }, 123 | { 124 | mode = ECBMode, 125 | key = Array.fromHex("08000000000000000000000000000000"), 126 | iv = Array.fromString(""), 127 | plaintext = Array.fromHex("0000000000000000"), 128 | ciphertext = Array.fromHex("794FE1DC2F80CD38"), 129 | padding = ZeroPadding 130 | }, 131 | { 132 | mode = ECBMode, 133 | key = Array.fromHex("04000000000000000000000000000000"), 134 | iv = Array.fromString(""), 135 | plaintext = Array.fromHex("0000000000000000"), 136 | ciphertext = Array.fromHex("15052BCDF21A1F1E"), 137 | padding = ZeroPadding 138 | }, 139 | { 140 | mode = ECBMode, 141 | key = Array.fromHex("02000000000000000000000000000000"), 142 | iv = Array.fromString(""), 143 | plaintext = Array.fromHex("0000000000000000"), 144 | ciphertext = Array.fromHex("3A830D0BDA044EBB"), 145 | padding = ZeroPadding 146 | }, 147 | { 148 | mode = ECBMode, 149 | key = Array.fromHex("01000000000000000000000000000000"), 150 | iv = Array.fromString(""), 151 | plaintext = Array.fromHex("0000000000000000"), 152 | ciphertext = Array.fromHex("8CA64DE9C1B123A7"), 153 | padding = ZeroPadding 154 | }, 155 | 156 | 157 | { 158 | mode = ECBMode, 159 | key = Array.fromHex("800000000000000000000000000000000000000000000000"), 160 | iv = Array.fromString(""), 161 | plaintext = Array.fromHex("0000000000000000"), 162 | ciphertext = Array.fromHex("95A8D72813DAA94D"), 163 | padding = ZeroPadding 164 | }, 165 | { 166 | mode = ECBMode, 167 | key = Array.fromHex("400000000000000000000000000000000000000000000000"), 168 | iv = Array.fromString(""), 169 | plaintext = Array.fromHex("0000000000000000"), 170 | ciphertext = Array.fromHex("0EEC1487DD8C26D5"), 171 | padding = ZeroPadding 172 | }, 173 | { 174 | mode = ECBMode, 175 | key = Array.fromHex("200000000000000000000000000000000000000000000000"), 176 | iv = Array.fromString(""), 177 | plaintext = Array.fromHex("0000000000000000"), 178 | ciphertext = Array.fromHex("7AD16FFB79C45926"), 179 | padding = ZeroPadding 180 | }, 181 | { 182 | mode = ECBMode, 183 | key = Array.fromHex("100000000000000000000000000000000000000000000000"), 184 | iv = Array.fromString(""), 185 | plaintext = Array.fromHex("0000000000000000"), 186 | ciphertext = Array.fromHex("D3746294CA6A6CF3"), 187 | padding = ZeroPadding 188 | }, 189 | { 190 | mode = ECBMode, 191 | key = Array.fromHex("080000000000000000000000000000000000000000000000"), 192 | iv = Array.fromString(""), 193 | plaintext = Array.fromHex("0000000000000000"), 194 | ciphertext = Array.fromHex("809F5F873C1FD761"), 195 | padding = ZeroPadding 196 | }, 197 | { 198 | mode = ECBMode, 199 | key = Array.fromHex("040000000000000000000000000000000000000000000000"), 200 | iv = Array.fromString(""), 201 | plaintext = Array.fromHex("0000000000000000"), 202 | ciphertext = Array.fromHex("C02FAFFEC989D1FC"), 203 | padding = ZeroPadding 204 | }, 205 | { 206 | mode = ECBMode, 207 | key = Array.fromHex("020000000000000000000000000000000000000000000000"), 208 | iv = Array.fromString(""), 209 | plaintext = Array.fromHex("0000000000000000"), 210 | ciphertext = Array.fromHex("4615AA1D33E72F10"), 211 | padding = ZeroPadding 212 | }, 213 | { 214 | mode = ECBMode, 215 | key = Array.fromHex("010000000000000000000000000000000000000000000000"), 216 | iv = Array.fromString(""), 217 | plaintext = Array.fromHex("0000000000000000"), 218 | ciphertext = Array.fromHex("8CA64DE9C1B123A7"), 219 | padding = ZeroPadding 220 | } 221 | 222 | 223 | }; 224 | 225 | for _, v in pairs(testVectors) do 226 | 227 | local cipher = v.mode.Cipher() 228 | .setKey(v.key) 229 | .setBlockCipher(DES3Cipher) 230 | .setPadding(v.padding); 231 | 232 | local res = cipher 233 | .init() 234 | .update(Stream.fromArray(v.iv)) 235 | .update(Stream.fromArray(v.plaintext)) 236 | .finish() 237 | .asHex(); 238 | 239 | assert(res == Array.toHex(v.ciphertext), 240 | String.format("test failed! DES encrypt expected(%s) got(%s)", Array.toHex(v.ciphertext), res)); 241 | 242 | local decipher = v.mode.Decipher() 243 | .setKey(v.key) 244 | .setBlockCipher(DES3Cipher) 245 | .setPadding(v.padding); 246 | 247 | res = decipher 248 | .init() 249 | .update(Stream.fromArray(v.iv)) 250 | .update(Stream.fromArray(v.ciphertext)) 251 | .finish() 252 | .asBytes(); 253 | 254 | assert(Array.toHex(res) == Array.toHex(v.plaintext), 255 | String.format("test failed! DES decrypt expected(%s) got(%s)", 256 | Array.toString(v.plaintext), Array.toString(res))); 257 | 258 | end 259 | -------------------------------------------------------------------------------- /test/DESCipherTests.lua: -------------------------------------------------------------------------------- 1 | local String = require("string"); 2 | 3 | local Array = require("lockbox.util.array"); 4 | local Stream = require("lockbox.util.stream"); 5 | 6 | local ECBMode = require("lockbox.cipher.mode.ecb"); 7 | 8 | local CBCMode = require("lockbox.cipher.mode.cbc"); 9 | 10 | local PKCS7Padding = require("lockbox.padding.pkcs7"); 11 | local ZeroPadding = require("lockbox.padding.zero"); 12 | 13 | local DESCipher = require("lockbox.cipher.des"); 14 | 15 | local testVectors = { 16 | { 17 | mode = ECBMode, 18 | key = Array.fromHex("8000000000000000"), 19 | iv = Array.fromString(""), 20 | plaintext = Array.fromHex("0000000000000000"), 21 | ciphertext= Array.fromHex("95A8D72813DAA94D"), 22 | padding = ZeroPadding 23 | }, 24 | { 25 | mode = ECBMode, 26 | key = Array.fromHex("4000000000000000"), 27 | iv = Array.fromString(""), 28 | plaintext = Array.fromHex("0000000000000000"), 29 | ciphertext = Array.fromHex("0EEC1487DD8C26D5"), 30 | padding = ZeroPadding 31 | }, 32 | { 33 | mode = ECBMode, 34 | key = Array.fromHex("2000000000000000"), 35 | iv = Array.fromString(""), 36 | plaintext = Array.fromHex("0000000000000000"), 37 | ciphertext = Array.fromHex("7AD16FFB79C45926"), 38 | padding = ZeroPadding 39 | }, 40 | { 41 | mode = ECBMode, 42 | key = Array.fromHex("1000000000000000"), 43 | iv = Array.fromString(""), 44 | plaintext = Array.fromHex("0000000000000000"), 45 | ciphertext = Array.fromHex("D3746294CA6A6CF3"), 46 | padding = ZeroPadding 47 | }, 48 | { 49 | mode = ECBMode, 50 | key = Array.fromHex("0800000000000000"), 51 | iv = Array.fromString(""), 52 | plaintext = Array.fromHex("0000000000000000"), 53 | ciphertext = Array.fromHex("809F5F873C1FD761"), 54 | padding = ZeroPadding 55 | }, 56 | { 57 | mode = ECBMode, 58 | key = Array.fromHex("0400000000000000"), 59 | iv = Array.fromString(""), 60 | plaintext = Array.fromHex("0000000000000000"), 61 | ciphertext = Array.fromHex("C02FAFFEC989D1FC"), 62 | padding = ZeroPadding 63 | }, 64 | { 65 | mode = ECBMode, 66 | key = Array.fromHex("0200000000000000"), 67 | iv = Array.fromString(""), 68 | plaintext = Array.fromHex("0000000000000000"), 69 | ciphertext = Array.fromHex("4615AA1D33E72F10"), 70 | padding = ZeroPadding 71 | }, 72 | { 73 | mode = ECBMode, 74 | key = Array.fromHex("0100000000000000"), 75 | iv = Array.fromString(""), 76 | plaintext = Array.fromHex("0000000000000000"), 77 | ciphertext = Array.fromHex("8CA64DE9C1B123A7"), 78 | padding = ZeroPadding 79 | }, 80 | 81 | { 82 | mode = CBCMode, 83 | key = Array.fromString("12345678"), 84 | iv = Array.fromString("abcdefgh"), 85 | plaintext = Array.fromString("This is the message to encrypt!!"), 86 | ciphertext = Array.fromHex("6CA9470C849D1CC1A59FFC148F1CB5E9CF1F5C0328A7E8756387FF4D0FE46050"), 87 | padding = PKCS7Padding 88 | }, 89 | 90 | }; 91 | 92 | for _, v in pairs(testVectors) do 93 | 94 | local cipher = v.mode.Cipher() 95 | .setKey(v.key) 96 | .setBlockCipher(DESCipher) 97 | .setPadding(v.padding); 98 | 99 | local res = cipher 100 | .init() 101 | .update(Stream.fromArray(v.iv)) 102 | .update(Stream.fromArray(v.plaintext)) 103 | .finish() 104 | .asHex(); 105 | 106 | assert(res == Array.toHex(v.ciphertext), 107 | String.format("test failed! DES encrypt expected(%s) got(%s)", Array.toHex(v.ciphertext), res)); 108 | 109 | local decipher = v.mode.Decipher() 110 | .setKey(v.key) 111 | .setBlockCipher(DESCipher) 112 | .setPadding(v.padding); 113 | 114 | res = decipher 115 | .init() 116 | .update(Stream.fromArray(v.iv)) 117 | .update(Stream.fromArray(v.ciphertext)) 118 | .finish() 119 | .asBytes(); 120 | 121 | assert(Array.toHex(res) == Array.toHex(v.plaintext), 122 | String.format("test failed! DES decrypt expected(%s) got(%s)", 123 | Array.toString(v.plaintext), Array.toString(res))); 124 | 125 | end 126 | -------------------------------------------------------------------------------- /test/HKDFTests.lua: -------------------------------------------------------------------------------- 1 | local HKDF = require("lockbox.kdf.hkdf"); 2 | local SHA1 = require("lockbox.digest.sha1"); 3 | local SHA256 = require("lockbox.digest.sha2_256"); 4 | 5 | local Array = require("lockbox.util.array"); 6 | 7 | local tests = { 8 | { 9 | ikm = Array.fromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), 10 | salt = Array.fromHex("000102030405060708090a0b0c"), 11 | info = Array.fromHex("f0f1f2f3f4f5f6f7f8f9"), 12 | outputLen = 42, 13 | digest = SHA256, 14 | output = "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865" 15 | }, 16 | { 17 | ikm = Array.fromHex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232" .. 18 | "425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"), 19 | salt = Array.fromHex("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283" .. 20 | "8485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7" .. 21 | "a8a9aaabacadaeaf"), 22 | info = Array.fromHex("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3" .. 23 | "d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7" .. 24 | "f8f9fafbfcfdfeff"), 25 | outputLen = 82, 26 | digest = SHA256, 27 | output = "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb" .. 28 | "41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87" 29 | }, 30 | { 31 | ikm = Array.fromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), 32 | salt = {}, 33 | info = nil, 34 | outputLen = 42, 35 | digest = SHA256, 36 | output = "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8" 37 | }, 38 | { 39 | ikm = Array.fromHex("0b0b0b0b0b0b0b0b0b0b0b"), 40 | salt = Array.fromHex("000102030405060708090a0b0c"), 41 | info = Array.fromHex("f0f1f2f3f4f5f6f7f8f9"), 42 | outputLen = 42, 43 | digest = SHA1, 44 | output = "085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896" 45 | }, 46 | { 47 | ikm = Array.fromHex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232" .. 48 | "425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"), 49 | salt = Array.fromHex("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283" .. 50 | "8485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7" .. 51 | "a8a9aaabacadaeaf"), 52 | info = Array.fromHex("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3" .. 53 | "d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7" .. 54 | "f8f9fafbfcfdfeff"), 55 | outputLen = 82, 56 | digest = SHA1, 57 | output = "0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334" .. 58 | "b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4" 59 | }, 60 | { 61 | ikm = Array.fromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), 62 | salt = {}, 63 | info = nil, 64 | outputLen = 42, 65 | digest = SHA1, 66 | output = "0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918" 67 | }, 68 | { 69 | ikm = Array.fromHex("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"), 70 | salt = nil, 71 | info = nil, 72 | outputLen = 42, 73 | digest = SHA1, 74 | output = "2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48" 75 | } 76 | }; 77 | 78 | for _, v in pairs(tests) do 79 | local res = HKDF() 80 | .setDigest(v.digest) 81 | .setInputKeyMaterial(v.ikm) 82 | .setSalt(v.salt) 83 | .setInfo(v.info) 84 | .setOutputLen(v.outputLen) 85 | .finish() 86 | .asHex(); 87 | 88 | assert(string.lower(res) == v.output, 89 | string.format("TEST FAILED IKM(%s) EXPECTED(%s) ACTUAL(%s)", 90 | Array.toHex(v.ikm), 91 | v.output, 92 | res)); 93 | end 94 | -------------------------------------------------------------------------------- /test/MD2Tests.lua: -------------------------------------------------------------------------------- 1 | local Stream = require("lockbox.util.stream"); 2 | local Digest = require("lockbox.digest.md2"); 3 | local String = require("string"); 4 | 5 | local test = {}; 6 | test[""] = "8350e5a3e24c153df2275c9f80692773"; 7 | test["a"] = "32ec01ec4a6dac72c0ab96fb34c0b5d1"; 8 | test["abc"] = "da853b0d3f88d99b30283a69e6ded6bb"; 9 | test["message digest"] = "ab4f496bfb2a530b219ff33031fe06b0"; 10 | test["abcdefghijklmnopqrstuvwxyz"] = "4e8ddff3650292ab5a4108c3aa47940b"; 11 | test["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"] = "da33def2a42df13975352846c30338cd"; 12 | test["12345678901234567890123456789012345678901234567890123456789012345678901234567890"] = 13 | "d5976f79d83d3a0dc9806c3c66f3efd8"; 14 | 15 | for k, v in pairs(test) do 16 | local message = k; 17 | local expected = v; 18 | local actual = Digest() 19 | .update(Stream.fromString(k)) 20 | .finish() 21 | .asHex(); 22 | 23 | assert(actual == expected, String.format("Test failed! MESSAGE(%s) Expected(%s) Actual(%s)", 24 | message, expected, actual)); 25 | 26 | end 27 | -------------------------------------------------------------------------------- /test/MD4Tests.lua: -------------------------------------------------------------------------------- 1 | local Stream = require("lockbox.util.stream"); 2 | local Digest = require("lockbox.digest.md4"); 3 | local String = require("string"); 4 | 5 | local test = {}; 6 | test[""] = "31d6cfe0d16ae931b73c59d7e0c089c0"; 7 | test["a"] = "bde52cb31de33e46245e05fbdbd6fb24"; 8 | test["abc"] = "a448017aaf21d8525fc10ae87aa6729d"; 9 | test["message digest"] = "d9130a8164549fe818874806e1c7014b"; 10 | test["abcdefghijklmnopqrstuvwxyz"] = "d79e1c308aa5bbcdeea8ed63df412da9"; 11 | test["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"] = "043f8582f241db351ce627e153e7f0e4"; 12 | test["12345678901234567890123456789012345678901234567890123456789012345678901234567890"] = 13 | "e33b4ddc9c38f2199c3e7b164fcc0536"; 14 | 15 | for k, v in pairs(test) do 16 | local message = k; 17 | local expected = v; 18 | local actual = Digest() 19 | .update(Stream.fromString(k)) 20 | .finish() 21 | .asHex(); 22 | 23 | assert(actual == expected, String.format("Test failed! MESSAGE(%s) Expected(%s) Actual(%s)", 24 | message, expected, actual)); 25 | 26 | 27 | end 28 | 29 | -------------------------------------------------------------------------------- /test/MD5Tests.lua: -------------------------------------------------------------------------------- 1 | local Stream = require("lockbox.util.stream"); 2 | local Digest = require("lockbox.digest.md5"); 3 | local String = require("string"); 4 | 5 | local test = {}; 6 | 7 | test["The quick brown fox jumps over the lazy dog"] = "9e107d9d372bb6826bd81d3542a419d6"; 8 | test["The quick brown fox jumps over the lazy dog."] = "e4d909c290d0fb1ca068ffaddf22cbd0"; 9 | test[""] = "d41d8cd98f00b204e9800998ecf8427e"; 10 | test["abc"] = "900150983cd24fb0d6963f7d28e17f72"; 11 | 12 | for k, v in pairs(test) do 13 | local message = k; 14 | local expected = v; 15 | local actual = Digest() 16 | .update(Stream.fromString(k)) 17 | .finish() 18 | .asHex(); 19 | 20 | assert(actual == expected, String.format("Test failed! MESSAGE(%s) Expected(%s) Actual(%s)", 21 | message, expected, actual)); 22 | 23 | end 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/PBKDF2Tests.lua: -------------------------------------------------------------------------------- 1 | local PBKDF2 = require("lockbox.kdf.pbkdf2"); 2 | local HMAC = require("lockbox.mac.hmac"); 3 | local SHA1 = require("lockbox.digest.sha1"); 4 | 5 | local String = require("string"); 6 | local Array = require("lockbox.util.array"); 7 | 8 | local tests = { 9 | { 10 | pass = Array.fromString("password"), 11 | salt = Array.fromString("salt"), 12 | iter = 1, 13 | blockLen = 20, 14 | dKeyLen = 20, 15 | prf = HMAC().setBlockSize(64).setDigest(SHA1); 16 | output = "0c60c80f961f0e71f3a9b524af6012062fe037a6" 17 | }, 18 | { 19 | pass = Array.fromString("password"), 20 | salt = Array.fromString("salt"), 21 | iter = 2, 22 | blockLen = 20, 23 | dKeyLen = 20, 24 | prf = HMAC().setBlockSize(64).setDigest(SHA1); 25 | output = "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957" 26 | }, 27 | { 28 | pass = Array.fromString("password"), 29 | salt = Array.fromString("salt"), 30 | iter = 4096, 31 | blockLen = 20, 32 | dKeyLen = 20, 33 | prf = HMAC().setBlockSize(64).setDigest(SHA1); 34 | output = "4b007901b765489abead49d926f721d065a429c1" 35 | }, 36 | 37 | }; 38 | 39 | for _, v in pairs(tests) do 40 | local res = PBKDF2() 41 | .setPRF(v.prf) 42 | .setBlockLen(v.blockLen) 43 | .setDKeyLen(v.dKeyLen) 44 | .setIterations(v.iter) 45 | .setSalt(v.salt) 46 | .setPassword(v.pass) 47 | .finish() 48 | .asHex(); 49 | 50 | assert(String.lower(res) == v.output, 51 | String.format("TEST FAILED PASSWORD(%s) EXPECTED(%s) ACTUAL(%s)", 52 | Array.toString(v.pass), 53 | v.output, 54 | res)); 55 | 56 | end 57 | -------------------------------------------------------------------------------- /test/RIPEMD128Tests.lua: -------------------------------------------------------------------------------- 1 | local Stream = require("lockbox.util.stream"); 2 | local Digest = require("lockbox.digest.ripemd128"); 3 | local String = require("string"); 4 | 5 | local test = {}; 6 | 7 | test[""] = "cdf26213a150dc3ecb610f18f6b38b46"; 8 | test["a"] = "86be7afa339d0fc7cfc785e72f578d33"; 9 | test["abc"] = "c14a12199c66e4ba84636b0f69144c77"; 10 | test["message digest"] = "9e327b3d6e523062afc1132d7df9d1b8"; 11 | test["abcdefghijklmnopqrstuvwxyz"] = "fd2aa607f71dc8f510714922b371834e"; 12 | test["abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"] = "a1aa0689d0fafa2ddc22e88b49133a06"; 13 | test["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"] = "d1e959eb179c911faea4624c60c5c702"; 14 | test["12345678901234567890123456789012345678901234567890123456789012345678901234567890"] = 15 | "3f45ef194732c2dbb2c4a2c769795fa3"; 16 | 17 | for k, v in pairs(test) do 18 | local message = k; 19 | local expected = v; 20 | local actual = Digest() 21 | .update(Stream.fromString(k)) 22 | .finish() 23 | .asHex(); 24 | 25 | assert(actual == expected, String.format("Test failed! MESSAGE(%s) Expected(%s) Actual(%s)", 26 | message, expected, actual)); 27 | 28 | end 29 | -------------------------------------------------------------------------------- /test/RIPEMD160Tests.lua: -------------------------------------------------------------------------------- 1 | local Stream = require("lockbox.util.stream"); 2 | local Digest = require("lockbox.digest.ripemd160"); 3 | local String = require("string"); 4 | 5 | local test = {}; 6 | 7 | test[""] = "9c1185a5c5e9fc54612808977ee8f548b2258d31"; 8 | test["a"] = "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"; 9 | test["abc"] = "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"; 10 | test["message digest"] = "5d0689ef49d2fae572b881b123a85ffa21595f36"; 11 | test["abcdefghijklmnopqrstuvwxyz"] = "f71c27109c692c1b56bbdceb5b9d2865b3708dbc"; 12 | test["abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"] = "12a053384a9c0c88e405a06c27dcf49ada62eb2b"; 13 | test["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"] = "b0e20b6e3116640286ed3a87a5713079b21f5189"; 14 | test["12345678901234567890123456789012345678901234567890123456789012345678901234567890"] = 15 | "9b752e45573d4b39f4dbd3323cab82bf63326bfb"; 16 | 17 | for k, v in pairs(test) do 18 | local message = k; 19 | local expected = v; 20 | local actual = Digest() 21 | .update(Stream.fromString(k)) 22 | .finish() 23 | .asHex(); 24 | 25 | assert(actual == expected, String.format("Test failed! MESSAGE(%s) Expected(%s) Actual(%s)", 26 | message, expected, actual)); 27 | 28 | end 29 | 30 | -------------------------------------------------------------------------------- /test/SHA1Tests.lua: -------------------------------------------------------------------------------- 1 | local Stream = require("lockbox.util.stream"); 2 | local Digest = require("lockbox.digest.sha1"); 3 | local String = require("string"); 4 | 5 | local test = {}; 6 | 7 | test[""] = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; 8 | test["abc"] = "a9993e364706816aba3e25717850c26c9cd0d89d"; 9 | test["abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"] = "84983e441c3bd26ebaae4aa1f95129e5e54670f1"; 10 | test["abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" .. 11 | "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"] = 12 | "a49b2446a02c645bf419f995b67091253a04a259"; 13 | 14 | for k, v in pairs(test) do 15 | local message = k; 16 | local expected = v; 17 | local actual = Digest() 18 | .update(Stream.fromString(k)) 19 | .finish() 20 | .asHex(); 21 | 22 | assert(actual == expected, String.format("Test failed! MESSAGE(%s) Expected(%s) Actual(%s)", 23 | message, expected, actual)); 24 | 25 | end 26 | -------------------------------------------------------------------------------- /test/SHA2_224Tests.lua: -------------------------------------------------------------------------------- 1 | local Stream = require("lockbox.util.stream"); 2 | local Digest = require("lockbox.digest.sha2_224"); 3 | local String = require("string"); 4 | 5 | local test = {}; 6 | 7 | test[""] = "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"; 8 | test["abc"] = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"; 9 | test["abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"] = 10 | "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525"; 11 | test["abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" .. 12 | "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"] = 13 | "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3"; 14 | 15 | for k, v in pairs(test) do 16 | local message = k; 17 | local expected = v; 18 | local actual = Digest() 19 | .update(Stream.fromString(k)) 20 | .finish() 21 | .asHex(); 22 | 23 | assert(actual == expected, String.format("Test failed! MESSAGE(%s) Expected(%s) Actual(%s)", 24 | message, expected, actual)); 25 | 26 | end 27 | -------------------------------------------------------------------------------- /test/SHA2_256Tests.lua: -------------------------------------------------------------------------------- 1 | local Stream = require("lockbox.util.stream"); 2 | local Digest = require("lockbox.digest.sha2_256"); 3 | local String = require("string"); 4 | 5 | local test = {}; 6 | 7 | test[""] = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; 8 | test["abc"] = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; 9 | test["abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"] = 10 | "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"; 11 | test["abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhij" .. 12 | "klmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"] = 13 | "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1"; 14 | 15 | for k, v in pairs(test) do 16 | local message = k; 17 | local expected = v; 18 | local actual = Digest() 19 | .update(Stream.fromString(k)) 20 | .finish() 21 | .asHex(); 22 | 23 | assert(actual == expected, String.format("Test failed! MESSAGE(%s) Expected(%s) Actual(%s)", 24 | message, expected, actual)); 25 | 26 | end 27 | 28 | -------------------------------------------------------------------------------- /test/TEACipherTests.lua: -------------------------------------------------------------------------------- 1 | local String = require("string"); 2 | 3 | local Array = require("lockbox.util.array"); 4 | local Stream = require("lockbox.util.stream"); 5 | 6 | local ECBMode = require("lockbox.cipher.mode.ecb"); 7 | 8 | local ZeroPadding = require("lockbox.padding.zero"); 9 | 10 | local TEACipher = require("lockbox.cipher.tea"); 11 | 12 | local testVectors = { 13 | 14 | { 15 | mode = ECBMode, 16 | key = Array.fromHex("00000000000000000000000000000000"), 17 | iv = Array.fromString(""), 18 | plaintext = Array.fromHex("0000000000000000"), 19 | ciphertext = Array.fromHex("41ea3a0a94baa940"), 20 | padding = ZeroPadding 21 | }, 22 | { 23 | mode = ECBMode, 24 | key = Array.fromHex("00000000000000000000000000000000"), 25 | iv = Array.fromString(""), 26 | plaintext = Array.fromHex("0102030405060708"), 27 | ciphertext = Array.fromHex("6a2f9cf3fccf3c55"), 28 | padding = ZeroPadding 29 | }, 30 | { 31 | mode = ECBMode, 32 | key = Array.fromHex("0123456712345678234567893456789a"), 33 | iv = Array.fromString(""), 34 | plaintext = Array.fromHex("0000000000000000"), 35 | ciphertext = Array.fromHex("34e943b0900f5dcb"), 36 | padding = ZeroPadding 37 | }, 38 | { 39 | mode = ECBMode, 40 | key = Array.fromHex("0123456712345678234567893456789a"), 41 | iv = Array.fromString(""), 42 | plaintext = Array.fromHex("0102030405060708"), 43 | ciphertext = Array.fromHex("773dc179878a81c0"), 44 | padding = ZeroPadding 45 | }, 46 | 47 | }; 48 | 49 | for _, v in pairs(testVectors) do 50 | 51 | local cipher = v.mode.Cipher() 52 | .setKey(v.key) 53 | .setBlockCipher(TEACipher) 54 | .setPadding(v.padding); 55 | 56 | local res = cipher 57 | .init() 58 | .update(Stream.fromArray(v.iv)) 59 | .update(Stream.fromArray(v.plaintext)) 60 | .finish() 61 | .asHex(); 62 | 63 | assert(res == Array.toHex(v.ciphertext), 64 | String.format("test failed! TEA encrypt expected(%s) got(%s)", Array.toHex(v.ciphertext), res)); 65 | 66 | local decipher = v.mode.Decipher() 67 | .setKey(v.key) 68 | .setBlockCipher(TEACipher) 69 | .setPadding(v.padding); 70 | 71 | local res2 = decipher 72 | .init() 73 | .update(Stream.fromArray(v.iv)) 74 | .update(Stream.fromArray(v.ciphertext)) 75 | .finish() 76 | .asHex(); 77 | 78 | assert(res2 == Array.toHex(v.plaintext), 79 | String.format("test failed! TEA decrypt expected(%s) got(%s)", Array.toHex(v.plaintext), res2)); 80 | 81 | end 82 | -------------------------------------------------------------------------------- /test/XTEACipherTests.lua: -------------------------------------------------------------------------------- 1 | local String = require("string"); 2 | 3 | local Array = require("lockbox.util.array"); 4 | local Stream = require("lockbox.util.stream"); 5 | 6 | local ECBMode = require("lockbox.cipher.mode.ecb"); 7 | 8 | local ZeroPadding = require("lockbox.padding.zero"); 9 | 10 | local XTEACipher = require("lockbox.cipher.xtea"); 11 | 12 | local testVectors = { 13 | 14 | { 15 | mode = ECBMode, 16 | key = Array.fromHex("27F917B1C1DA899360E2ACAAA6EB923D"), 17 | iv = Array.fromString(""), 18 | plaintext = Array.fromHex("AF20A390547571AA"), 19 | ciphertext = Array.fromHex("D26428AF0A202283"), 20 | padding = ZeroPadding 21 | }, 22 | { 23 | mode = ECBMode, 24 | key = Array.fromHex("31415926535897932384626433832795"), 25 | iv = Array.fromString(""), 26 | plaintext = Array.fromHex("0288419716939937"), 27 | ciphertext = Array.fromHex("46E2007D58BBC2EA"), 28 | padding = ZeroPadding 29 | }, 30 | { 31 | mode = ECBMode, 32 | key = Array.fromHex("1234ABC1234ABC1234ABC1234ABC1234"), 33 | iv = Array.fromString(""), 34 | plaintext = Array.fromHex("ABC1234ABC1234AB"), 35 | ciphertext = Array.fromHex("5C0754C1F6F0BD9B"), 36 | padding = ZeroPadding 37 | }, 38 | { 39 | mode = ECBMode, 40 | key = Array.fromHex("ABC1234ABC1234ABC1234ABC1234ABC1"), 41 | iv = Array.fromString(""), 42 | plaintext = Array.fromHex("234ABC1234ABC123"), 43 | ciphertext = Array.fromHex("CDFCC72C24BC116B"), 44 | padding = ZeroPadding 45 | }, 46 | { 47 | mode = ECBMode, 48 | key = Array.fromHex("DEADBEEFDEADBEEFDEADBEEFDEADBEEF"), 49 | iv = Array.fromString(""), 50 | plaintext = Array.fromHex("DEADBEEFDEADBEEF"), 51 | ciphertext = Array.fromHex("FAF28CB50940C0E0"), 52 | padding = ZeroPadding 53 | }, 54 | { 55 | mode = ECBMode, 56 | key = Array.fromHex("DEADBEEFDEADBEEFDEADBEEFDEADBEEF"), 57 | iv = Array.fromString(""), 58 | plaintext = Array.fromHex("9647A9189EC565D5"), 59 | ciphertext = Array.fromHex("DEADBEEFDEADBEEF"), 60 | padding = ZeroPadding 61 | }, 62 | }; 63 | 64 | for _, v in pairs(testVectors) do 65 | 66 | local cipher = v.mode.Cipher() 67 | .setKey(v.key) 68 | .setBlockCipher(XTEACipher) 69 | .setPadding(v.padding); 70 | 71 | local res = cipher 72 | .init() 73 | .update(Stream.fromArray(v.iv)) 74 | .update(Stream.fromArray(v.plaintext)) 75 | .finish() 76 | .asHex(); 77 | 78 | assert(res == Array.toHex(v.ciphertext), 79 | String.format("test failed! TEA encrypt expected(%s) got(%s)", Array.toHex(v.ciphertext), res)); 80 | 81 | local decipher = v.mode.Decipher() 82 | .setKey(v.key) 83 | .setBlockCipher(XTEACipher) 84 | .setPadding(v.padding); 85 | 86 | local res2 = decipher 87 | .init() 88 | .update(Stream.fromArray(v.iv)) 89 | .update(Stream.fromArray(v.ciphertext)) 90 | .finish() 91 | .asHex(); 92 | 93 | assert(res2 == Array.toHex(v.plaintext), 94 | String.format("test failed! TEA decrypt expected(%s) got(%s)", Array.toHex(v.plaintext), res2)); 95 | 96 | end 97 | --------------------------------------------------------------------------------