Commit de938c70 authored by Hanspeter Portner's avatar Hanspeter Portner

api: add base64, ascii85 libraries.

* add base64 library
* add ascii85 library
* improve aes-128 library
parent b90942a9
......@@ -10,8 +10,8 @@ include_directories(${PROJECT_SOURCE_DIR}/osc.lv2)
include_directories(${PROJECT_SOURCE_DIR}/timely.lv2)
include_directories(${PROJECT_SOURCE_DIR}/xpress.lv2)
include_directories(${PROJECT_SOURCE_DIR}/lua-5.3.4)
include_directories(${PROJECT_SOURCE_DIR}/lpeg-1.0.1)
include_directories(${PROJECT_SOURCE_DIR}/tiny-AES128-C)
include_directories(${PROJECT_SOURCE_DIR}/laes128)
include_directories(${PROJECT_SOURCE_DIR}/api)
include_directories(${PROJECT_SOURCE_DIR}/ui)
include_directories(${PROJECT_SOURCE_DIR}/include)
......@@ -238,11 +238,11 @@ add_library(lua OBJECT
lua-5.3.4/lvm.c
lua-5.3.4/lzio.c
#lua-5.3.4/lbitlib.c
lua-5.3.4/liolib.c
lua-5.3.4/loadlib.c
#lua-5.3.4/lbitlib.c
#lua-5.3.4/loslib.c
#lua-5.3.4/linit.c
lua-5.3.4/loadlib.c
lua-5.3.4/ldblib.c
lua-5.3.4/lbaselib.c
......@@ -264,6 +264,22 @@ add_library(lpeg OBJECT
set_target_properties(lpeg PROPERTIES POSITION_INDEPENDENT_CODE true) # -fPIC
set_target_properties(lpeg PROPERTIES INTERPROCEDURAL_OPTIMIZATION true) # -flto
add_library(lbase64 OBJECT
lbase64/lbase64.c)
set_target_properties(lbase64 PROPERTIES POSITION_INDEPENDENT_CODE true) # -fPIC
set_target_properties(lbase64 PROPERTIES INTERPROCEDURAL_OPTIMIZATION true) # -flto
add_library(lascii85 OBJECT
lascii85/lascii85.c)
set_target_properties(lascii85 PROPERTIES POSITION_INDEPENDENT_CODE true) # -fPIC
set_target_properties(lascii85 PROPERTIES INTERPROCEDURAL_OPTIMIZATION true) # -flto
add_library(laes128 OBJECT
laes128/laes128.c
tiny-AES128-C/aes.c)
set_target_properties(laes128 PROPERTIES POSITION_INDEPENDENT_CODE true) # -fPIC
set_target_properties(laes128 PROPERTIES INTERPROCEDURAL_OPTIMIZATION true) # -flto
add_library(api OBJECT
api/api.c
api/api_atom.c
......@@ -275,8 +291,7 @@ add_library(api OBJECT
api/api_state.c
api/api_parameter.c
api/api_vm.c
tlsf-3.0/tlsf.c
tiny-AES128-C/aes.c)
tlsf-3.0/tlsf.c)
set_target_properties(api PROPERTIES POSITION_INDEPENDENT_CODE true) # -fPIC
set_target_properties(api PROPERTIES INTERPROCEDURAL_OPTIMIZATION true) # -flto
......@@ -287,7 +302,10 @@ add_library(moony MODULE
plugin/caxca.c
$<TARGET_OBJECTS:api>
$<TARGET_OBJECTS:lua>
$<TARGET_OBJECTS:lpeg>)
$<TARGET_OBJECTS:lpeg>
$<TARGET_OBJECTS:lbase64>
$<TARGET_OBJECTS:lascii85>
$<TARGET_OBJECTS:laes128>)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
target_compile_definitions(moony PUBLIC -DLUA_USE_LINUX)
elseif(WIN32)
......@@ -317,7 +335,10 @@ if(BUILD_TESTING)
test/moony_test.c
$<TARGET_OBJECTS:api>
$<TARGET_OBJECTS:lua>
$<TARGET_OBJECTS:lpeg>)
$<TARGET_OBJECTS:lpeg>
$<TARGET_OBJECTS:lbase64>
$<TARGET_OBJECTS:lascii85>
$<TARGET_OBJECTS:laes128>)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
target_compile_definitions(moony_test PUBLIC -DLUA_USE_LINUX)
elseif(WIN32)
......
......@@ -20,9 +20,6 @@
#include <inttypes.h>
#include <stdatomic.h>
#define ECB 1
#define CBC 0
#include <aes.h>
#include <osc.lv2/endian.h>
#include <api_atom.h>
......@@ -372,122 +369,6 @@ _log(lua_State *L)
return 0;
}
__realtime static bool
_parse_key(lua_State *L, int idx, uint8_t key [16])
{
size_t key_len;
const char *pass = luaL_checklstring(L, idx, &key_len);
switch(key_len)
{
case 16: // raw key
memcpy(key, pass, 16);
break;
case 32: // hex-encoded key
for(unsigned i=0; i<16; i++)
{
if(sscanf(&pass[i*2], "%02"SCNx8, &key[i]) != 1)
return false; // sscanf failed
}
break;
default: // invalid key
return false;
}
return true; // success
}
__realtime static int
_lencrypt(lua_State *L)
{
size_t input_len;
const uint8_t *input = (const uint8_t *)luaL_checklstring(L, 1, &input_len);
uint8_t key [16];
if(!_parse_key(L, 2, key))
{
lua_pushnil(L);
return 1;
}
const size_t offset_len = sizeof(uint32_t); // length of size prefix
const uint32_t output_len = ((input_len + 15) & (~15)) + offset_len; // round to next 16 byte boundary
luaL_Buffer buf;
uint8_t *dst = (uint8_t *)luaL_buffinitsize(L, &buf, output_len);
*(uint32_t *)dst = htobe32(input_len); // write chunk size
aes_t aes;
for(unsigned i=0; i<input_len; i+=16)
{
uint8_t temp [16];
const unsigned rem = input_len - i;
const unsigned len = rem < 16 ? rem : 16;
if(len < 16)
memset(temp, 0x0, 16); // pad remainder
memcpy(temp, &input[i], 16);
AES128_ECB_encrypt(&aes, temp, key, &dst[offset_len + i]);
}
luaL_addsize(&buf, output_len);
luaL_pushresult(&buf);
return 1;
}
__realtime static int
_ldecrypt(lua_State *L)
{
size_t input_len;
const uint8_t *input = (const uint8_t *)luaL_checklstring(L, 1, &input_len);
uint8_t key [16];
if(!_parse_key(L, 2, key))
{
lua_pushnil(L);
return 1;
}
const uint32_t output_len = be32toh(*(uint32_t *)input); // read chunk size
const size_t offset_len = sizeof(uint32_t); // length of size prefix
luaL_Buffer buf;
uint8_t *dst = (uint8_t *)luaL_buffinitsize(L, &buf, output_len);
aes_t aes;
for(unsigned i=0; i<output_len; i+=16)
{
uint8_t temp [16];
memcpy(temp, &input[offset_len + i], 16);
AES128_ECB_decrypt(&aes, temp, key, &dst[i]);
}
luaL_addsize(&buf, output_len);
luaL_pushresult(&buf);
// discriminate between code and string
if(lua_isstring(L, -1))
{
size_t str_len;
const char *str = lua_tolstring(L, -1, &str_len);
if(luaL_loadbuffer(L, str, str_len, "decrypt") == LUA_OK)
{
return 1; // return code parsed from decrypted string
}
else
{
lua_pop(L, 1); // pop error code;
return 1; // return decrypted string
}
}
lua_pushnil(L);
return 1;
}
__realtime LV2_Atom_Forge_Ref
_sink_rt(LV2_Atom_Forge_Sink_Handle handle, const void *buf, uint32_t size)
{
......@@ -1947,12 +1828,6 @@ moony_open(moony_t *moony, lua_State *L)
lua_newtable(L);
lua_rawseti(L, LUA_REGISTRYINDEX, UDATA_OFFSET + MOONY_UDATA_COUNT + MOONY_CCLOSURE_COUNT + MOONY_UPCLOSURE_SEQUENCE_PACK);
lua_pushcclosure(L, _lencrypt, 0);
lua_setglobal(L, "encrypt");
lua_pushcclosure(L, _ldecrypt, 0);
lua_setglobal(L, "decrypt");
#undef SET_MAP
}
......
......@@ -28,7 +28,12 @@
#include <lualib.h>
#include <lauxlib.h>
#include <laes128.h>
//FIXME put those into a header
extern int luaopen_lpeg(lua_State *L);
extern int luaopen_base64(lua_State *L);
extern int luaopen_ascii85(lua_State *L);
//#define MOONY_LOG_MEM
#ifdef MOONY_LOG_MEM
......@@ -163,7 +168,10 @@ moony_vm_init(moony_vm_t *vm, size_t mem_size, bool testing)
if(!vm->L)
return -1;
const int n = lua_gettop(vm->L);
luaL_requiref(vm->L, "base", luaopen_base, 0);
luaL_requiref(vm->L, "coroutine", luaopen_coroutine, 1);
luaL_requiref(vm->L, "table", luaopen_table, 1);
luaL_requiref(vm->L, "string", luaopen_string, 1);
......@@ -171,14 +179,21 @@ moony_vm_init(moony_vm_t *vm, size_t mem_size, bool testing)
luaL_requiref(vm->L, "utf8", luaopen_utf8, 1);
luaL_requiref(vm->L, "debug", luaopen_debug, 1);
luaL_requiref(vm->L, "lpeg", luaopen_lpeg, 1);
luaL_requiref(vm->L, "base64", luaopen_base64, 1);
luaL_requiref(vm->L, "ascii85", luaopen_ascii85, 1);
luaL_requiref(vm->L, "aes128", luaopen_aes128, 1);
if(testing)
{
luaL_requiref(vm->L, "io", luaopen_io, 1);
luaL_requiref(vm->L, "package", luaopen_package, 1);
//luaL_requiref(vm->L, "os", luaopen_os, 1);
//luaL_requiref(vm->L, "bit32", luaopen_bit32, 1);
luaL_requiref(vm->L, "package", luaopen_package, 1);
}
lua_settop(vm->L, n);
if(!testing)
{
// clear dofile
......@@ -190,9 +205,6 @@ moony_vm_init(moony_vm_t *vm, size_t mem_size, bool testing)
lua_setglobal(vm->L, "loadfile");
}
luaL_requiref(vm->L, "lpeg", luaopen_lpeg, 1);
lua_pop(vm->L, 8);
#ifdef USE_MANUAL_GC
// manual garbage collector
lua_gc(vm->L, LUA_GCSTOP, 0); // disable automatic garbage collection
......
/*
* Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch)
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the Artistic License 2.0 as published by
* The Perl Foundation.
*
* This source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Artistic License 2.0 for more details.
*
* You should have received a copy of the Artistic License 2.0
* along the source as a COPYING file. If not, obtain it from
* http://www.perlfoundation.org/artistic_license_2_0.
*/
#include <stdbool.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include <laes128.h>
#include <lauxlib.h>
#define ECB 0
#define CBC 1
#include <aes.h>
static bool
_parse_key(lua_State *L, int idx, uint8_t key [16])
{
size_t key_len;
const char *pass = luaL_checklstring(L, idx, &key_len);
switch(key_len)
{
case 16: // raw key
memcpy(key, pass, 16);
break;
case 32: // hex-encoded key
for(unsigned i=0; i<16; i++)
{
if(sscanf(&pass[i*2], "%02"SCNx8, &key[i]) != 1)
return false; // sscanf failed
}
break;
default: // invalid key
return false;
}
return true; // success
}
static const uint8_t iv [] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
static int
_laes128_encode(lua_State *L)
{
size_t input_len;
const uint8_t *input = (const uint8_t *)luaL_checklstring(L, 1, &input_len);
uint8_t key [16];
if(!_parse_key(L, 2, key))
{
lua_pushnil(L);
return 1;
}
const size_t output_len = ((input_len + 15) & (~15)); // round to next 16 byte boundary
luaL_Buffer input_buf;
luaL_Buffer output_buf;
// create a 16-byte padded copy of input
uint8_t *input_copy = (uint8_t *)luaL_buffinitsize(L, &input_buf, output_len);
memset(input_copy + output_len - 16, 0x0, 16); // pad last 16 bytes
memcpy(input_copy, input, input_len);
luaL_pushresultsize(&input_buf, output_len);
uint8_t *output = (uint8_t *)luaL_buffinitsize(L, &output_buf, output_len);
aes_t aes;
memset(&aes, 0x0, sizeof(aes_t));
AES128_CBC_encrypt_buffer(&aes, output, input_copy, output_len, key, iv);
luaL_pushresultsize(&output_buf, output_len);
lua_pushinteger(L, input_len);
return 2;
}
static int
_laes128_decode(lua_State *L)
{
size_t input_len;
const uint8_t *input = (const uint8_t *)luaL_checklstring(L, 1, &input_len);
uint8_t key [16];
if(!_parse_key(L, 2, key))
{
lua_pushnil(L);
return 1;
}
const size_t encoded_len = luaL_optinteger(L, 3, input_len);
const size_t output_len = ((input_len + 15) & (~15)); // round to next 16 byte boundary
luaL_Buffer input_buf;
luaL_Buffer output_buf;
// create a 16-byte padded copy of input
uint8_t *input_copy = (uint8_t *)luaL_buffinitsize(L, &input_buf, output_len);
memset(input_copy + output_len - 16, 0x0, 16); // pad last 16 bytes
memcpy(input_copy, input, input_len);
luaL_pushresultsize(&input_buf, output_len);
uint8_t *output = (uint8_t *)luaL_buffinitsize(L, &output_buf, output_len);
aes_t aes;
memset(&aes, 0x0, sizeof(aes_t));
AES128_CBC_decrypt_buffer(&aes, output, input_copy, output_len, key, iv);
// crop output to encoded_len
luaL_pushresultsize(&output_buf, encoded_len);
return 1;
}
static const luaL_Reg laes128 [] = {
{"encode", _laes128_encode},
{"decode", _laes128_decode},
{NULL, NULL}
};
LUA_API int
luaopen_aes128(lua_State *L)
{
luaL_newlib(L, laes128);
return 1;
}
/*
* Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch)
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the Artistic License 2.0 as published by
* The Perl Foundation.
*
* This source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Artistic License 2.0 for more details.
*
* You should have received a copy of the Artistic License 2.0
* along the source as a COPYING file. If not, obtain it from
* http://www.perlfoundation.org/artistic_license_2_0.
*/
#include <lua.h>
LUA_API int
luaopen_aes128(lua_State *L);
# makefile for ascii85 library for Lua
# change these to reflect your Lua installation
LUA= /tmp/lhf/lua-5.3.3
LUAINC= $(LUA)/src
LUALIB= $(LUA)/src
LUABIN= $(LUA)/src
# these will probably work if Lua has been installed globally
#LUA= /usr/local
#LUAINC= $(LUA)/include
#LUALIB= $(LUA)/lib
#LUABIN= $(LUA)/bin
# probably no need to change anything below here
CC= gcc -std=c99
CFLAGS= $(INCS) $(WARN) -O2 $G
WARN= -pedantic -Wall -Wextra
INCS= -I$(LUAINC)
MAKESO= $(CC) -shared
#MAKESO= $(CC) -bundle -undefined dynamic_lookup
MYNAME= ascii85
MYLIB= l$(MYNAME)
T= $(MYNAME).so
OBJS= $(MYLIB).o
TEST= test.lua
all: test
test: $T
$(LUABIN)/lua $(TEST)
o: $(MYLIB).o
so: $T
$T: $(OBJS)
$(MAKESO) -o $@ $(OBJS)
clean:
rm -f $(OBJS) $T core core.*
doc:
@echo "$(MYNAME) library:"
@fgrep '/**' $(MYLIB).c | cut -f2 -d/ | tr -d '*' | sort | column
# eof
This is an ascii85 library for Lua 5.2. For information on ascii85 see
http://en.wikipedia.org/wiki/Ascii85
To try the library, just edit Makefile to reflect your installation of Lua and
then run make. This will build the library and run a simple test. For detailed
installation instructions, see
http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/install.html
There is no manual but the library is simple and intuitive; see the summary
below. Read also test.lua, which shows the library in action.
This code is hereby placed in the public domain.
Please send comments, suggestions, and bug reports to lhf@tecgraf.puc-rio.br .
-------------------------------------------------------------------------------
ascii85 library:
decode(s) encode(s) version
-------------------------------------------------------------------------------
/*
* lascii85.c
* ascii85 encoding and decoding for Lua 5.2
* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
* 27 Sep 2012 19:36:45
* This code is hereby placed in the public domain.
*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#define MYNAME "ascii85"
#define MYVERSION MYNAME " library for " LUA_VERSION " / Sep 2012"
#define uint unsigned int
static void encode(luaL_Buffer *b, uint c1, uint c2, uint c3, uint c4, int n)
{
unsigned long tuple=c4+256UL*(c3+256UL*(c2+256UL*c1));
if (tuple==0 && n==4)
luaL_addlstring(b,"z",1);
else
{
int i;
char s[5];
for (i=0; i<5; i++) {
s[4-i] = '!' + (tuple % 85);
tuple /= 85;
}
luaL_addlstring(b,s,n+1);
}
}
static int Lencode(lua_State *L) /** encode(s) */
{
size_t l;
const unsigned char *s=(const unsigned char*)luaL_checklstring(L,1,&l);
luaL_Buffer b;
int n;
luaL_buffinit(L,&b);
luaL_addlstring(&b,"<~",2);
for (n=l/4; n--; s+=4) encode(&b,s[0],s[1],s[2],s[3],4);
switch (l%4)
{
case 1: encode(&b,s[0],0,0,0,1); break;
case 2: encode(&b,s[0],s[1],0,0,2); break;
case 3: encode(&b,s[0],s[1],s[2],0,3); break;
}
luaL_addlstring(&b,"~>",2);
luaL_pushresult(&b);
return 1;
}
static void decode(luaL_Buffer *b, int c1, int c2, int c3, int c4, int c5, int n)
{
unsigned long tuple=c5+85L*(c4+85L*(c3+85L*(c2+85L*c1)));
char s[4];
switch (--n)
{
case 4: s[3]=tuple;
case 3: s[2]=tuple >> 8;
case 2: s[1]=tuple >> 16;
case 1: s[0]=tuple >> 24;
}
luaL_addlstring(b,s,n);
}
static int Ldecode(lua_State *L) /** decode(s) */
{
size_t l;
const char *s=luaL_checklstring(L,1,&l);
luaL_Buffer b;
int n=0;
char t[5];
if (*s++!='<') return 0;
if (*s++!='~') return 0;
luaL_buffinit(L,&b);
for (;;)
{
int c=*s++;
switch (c)
{
default:
if (c<'!' || c>'u') return 0;
t[n++]=c-'!';
if (n==5)
{
decode(&b,t[0],t[1],t[2],t[3],t[4],5);
n=0;
}
break;
case 'z':
luaL_addlstring(&b,"\0\0\0\0",4);
break;
case '~':
if (*s!='>') return 0;
switch (n)
{
case 1: decode(&b,t[0],85,0,0,0,1); break;
case 2: decode(&b,t[0],t[1],85,0,0,2); break;
case 3: decode(&b,t[0],t[1],t[2],85,0,3); break;
case 4: decode(&b,t[0],t[1],t[2],t[3],85,4); break;
}
luaL_pushresult(&b);
return 1;
case '\n': case '\r': case '\t': case ' ':
case '\0': case '\f': case '\b': case 0177:
break;
}
}
return 0;
}
static const luaL_Reg R[] =
{
{ "encode", Lencode },
{ "decode", Ldecode },
{ NULL, NULL }
};
LUALIB_API int luaopen_ascii85(lua_State *L)
{
luaL_newlib(L,R);
lua_pushliteral(L,"version"); /** version */
lua_pushliteral(L,MYVERSION);
lua_settable(L,-3);
return 1;
}
-- test ascii85 library
local ascii85=require"ascii85"
print(ascii85.version)
print""
function test(s)
--print""
--print(string.len(s),s)
local a=ascii85.encode(s)
--print(string.len(a),a)
local b=ascii85.decode(a)
--print(string.len(b),b)
print(string.len(s),b==s,a,s)
assert(b==s)
end
for i=0,13 do
local s=string.sub("Lua-scripting-language",1,i)
test(s)
end
function test(p)
print("testing prefix "..string.len(p))
for i=0,255 do
local s=p..string.char(i)
local a=ascii85.encode(s)
local b=ascii85.decode(a)
assert(b==s,i)
end
end
print""
test""
test"x"
test"xy"
test"xyz"
print""
print(ascii85.version)
-- eof
# makefile for base64 library for Lua
# change these to reflect your Lua installation
LUA= /tmp/lhf/lua-5.3.2
LUAINC= $(LUA)/src
LUALIB= $(LUA)/src
LUABIN= $(LUA)/src
# these will probably work if Lua has been installed globally
#LUA= /usr/local
#LUAINC= $(LUA)/include
#LUALIB= $(LUA)/lib
#LUABIN= $(LUA)/bin
# probably no need to change anything below here
CC= gcc -std=c99
CFLAGS= $(INCS) $(WARN) -O2 $G
WARN= -pedantic -Wall -Wextra
INCS= -I$(LUAINC)
MAKESO= $(CC) -shared
#MAKESO= $(CC) -bundle -undefined dynamic_lookup
MYNAME= base64
MYLIB= l$(MYNAME)
T= $(MYNAME).so
OBJS= $(MYLIB).o
TEST= test.lua
all: test
test: $T
$(LUABIN)/lua $(TEST)
o: $(MYLIB).o
so: $T
$T: $(OBJS)
$(MAKESO) -o $@ $(OBJS)
clean:
rm -f $(OBJS) $T core core.*
doc:
@echo "$(MYNAME) library:"
@fgrep '/**' $(MYLIB).c | cut -f2 -d/ | tr -d '*' | sort | column
# eof