Fixed asm files and .gitignore

canary
WolverinDEV 2018-10-04 23:03:35 +02:00
parent a5f5829c56
commit 13795e4fd1
11 changed files with 1132 additions and 6 deletions

6
.gitignore vendored
View File

@ -5,16 +5,10 @@
**.css
!vendor/**/*.css
asm/build/
generated/
node_modules/
auth/certs/
auth/js/auth.js.map
.idea/
asm/**
!asm/identity/
!asm/src/
!asm/CMakeLists.txt
!asm/make_opus.sh
web/*-environment/

2
asm/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
generated/
build/

458
asm/identity/INIReader.h Normal file
View File

@ -0,0 +1,458 @@
// Read an INI file into easy-to-access name/value pairs.
// inih and INIReader are released under the New BSD license (see LICENSE.txt).
// Go to the project home page for more info:
//
// https://github.com/benhoyt/inih
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
https://github.com/benhoyt/inih
*/
#ifndef __INI_H__
#define __INI_H__
/* Make this header file easier to include in C++ code */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
/* Typedef for prototype of handler function. */
typedef int (*ini_handler)(void* user, const char* section,
const char* name, const char* value);
/* Typedef for prototype of fgets-style reader function. */
typedef char* (*ini_reader)(char* str, int num, void* stream);
/* Parse given INI-style file. May have [section]s, name=value pairs
(whitespace stripped), and comments starting with ';' (semicolon). Section
is "" if name=value pair parsed before any section heading. name:value
pairs are also supported as a concession to Python's configparser.
For each name=value pair parsed, call handler function with given user
pointer as well as section, name, and value (data only valid for duration
of handler call). Handler should return nonzero on success, zero on error.
Returns 0 on success, line number of first error on parse error (doesn't
stop on first error), -1 on file open error, or -2 on memory allocation
error (only when INI_USE_STACK is zero).
*/
int ini_parse(const char* filename, ini_handler handler, void* user);
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
close the file when it's finished -- the caller must do that. */
int ini_parse_file(FILE* file, ini_handler handler, void* user);
inline int ini_parse_message(const std::string& message, ini_handler handler, void* user);
/* Same as ini_parse(), but takes an ini_reader function pointer instead of
filename. Used for implementing custom or string-based I/O. */
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
void* user);
/* Nonzero to allow multi-line value parsing, in the style of Python's
configparser. If allowed, ini_parse() will call the handler with the same
name for each subsequent line parsed. */
#ifndef INI_ALLOW_MULTILINE
#define INI_ALLOW_MULTILINE 1
#endif
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
the file. See http://code.google.com/p/inih/issues/detail?id=21 */
#ifndef INI_ALLOW_BOM
#define INI_ALLOW_BOM 1
#endif
/* Nonzero to allow inline comments (with valid inline comment characters
specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
Python 3.2+ configparser behaviour. */
#ifndef INI_ALLOW_INLINE_COMMENTS
#define INI_ALLOW_INLINE_COMMENTS 1
#endif
#ifndef INI_INLINE_COMMENT_PREFIXES
#define INI_INLINE_COMMENT_PREFIXES ";"
#endif
/* Nonzero to use stack, zero to use heap (malloc/free). */
#ifndef INI_USE_STACK
#define INI_USE_STACK 1
#endif
/* Stop parsing on first error (default is to keep parsing). */
#ifndef INI_STOP_ON_FIRST_ERROR
#define INI_STOP_ON_FIRST_ERROR 0
#endif
/* Maximum line length for any line in INI file. */
#ifndef INI_MAX_LINE
#define INI_MAX_LINE 200
#endif
#ifdef __cplusplus
}
#endif
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
https://github.com/benhoyt/inih
*/
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sstream>
#if !INI_USE_STACK
#include <stdlib.h>
#endif
#define MAX_SECTION 50
#define MAX_NAME 50
/* Strip whitespace chars off end of given string, in place. Return s. */
inline static char* rstrip(char* s)
{
char* p = s + strlen(s);
while (p > s && isspace((unsigned char)(*--p)))
*p = '\0';
return s;
}
/* Return pointer to first non-whitespace char in given string. */
inline static char* lskip(const char* s)
{
while (*s && isspace((unsigned char)(*s)))
s++;
return (char*)s;
}
/* Return pointer to first char (of chars) or inline comment in given string,
or pointer to null at end of string if neither found. Inline comment must
be prefixed by a whitespace character to register as a comment. */
inline static char* find_chars_or_comment(const char* s, const char* chars)
{
#if INI_ALLOW_INLINE_COMMENTS
int was_space = 0;
while (*s && (!chars || !strchr(chars, *s)) &&
!(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
was_space = isspace((unsigned char)(*s));
s++;
}
#else
while (*s && (!chars || !strchr(chars, *s))) {
s++;
}
#endif
return (char*)s;
}
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
inline static char* strncpy0(char* dest, const char* src, size_t size)
{
strncpy(dest, src, size);
dest[size - 1] = '\0';
return dest;
}
/* See documentation in header file. */
inline int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
void* user)
{
/* Uses a fair bit of stack (use heap instead if you need to) */
#if INI_USE_STACK
char line[INI_MAX_LINE];
#else
char* line;
#endif
char section[MAX_SECTION] = "";
char prev_name[MAX_NAME] = "";
char* start;
char* end;
char* name;
char* value;
int lineno = 0;
int error = 0;
#if !INI_USE_STACK
line = (char*)malloc(INI_MAX_LINE);
if (!line) {
return -2;
}
#endif
/* Scan through stream line by line */
while (reader(line, INI_MAX_LINE, stream) != NULL) {
lineno++;
start = line;
#if INI_ALLOW_BOM
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
(unsigned char)start[1] == 0xBB &&
(unsigned char)start[2] == 0xBF) {
start += 3;
}
#endif
start = lskip(rstrip(start));
if (*start == ';' || *start == '#') {
/* Per Python configparser, allow both ; and # comments at the
start of a line */
}
#if INI_ALLOW_MULTILINE
else if (*prev_name && *start && start > line) {
#if INI_ALLOW_INLINE_COMMENTS
end = find_chars_or_comment(start, NULL);
if (*end)
*end = '\0';
rstrip(start);
#endif
/* Non-blank line with leading whitespace, treat as continuation
of previous name's value (as per Python configparser). */
if (!handler(user, section, prev_name, start) && !error)
error = lineno;
}
#endif
else if (*start == '[') {
/* A "[section]" line */
end = find_chars_or_comment(start + 1, "]");
if (*end == ']') {
*end = '\0';
strncpy0(section, start + 1, sizeof(section));
*prev_name = '\0';
}
else if (!error) {
/* No ']' found on section line */
error = lineno;
}
}
else if (*start) {
/* Not a comment, must be a name[=:]value pair */
end = find_chars_or_comment(start, "=:");
if (*end == '=' || *end == ':') {
*end = '\0';
name = rstrip(start);
value = lskip(end + 1);
#if INI_ALLOW_INLINE_COMMENTS
end = find_chars_or_comment(value, NULL);
if (*end)
*end = '\0';
#endif
rstrip(value);
/* Valid name[=:]value pair found, call handler */
strncpy0(prev_name, name, sizeof(prev_name));
if (!handler(user, section, name, value) && !error)
error = lineno;
}
else if (!error) {
/* No '=' or ':' found on name[=:]value line */
error = lineno;
}
}
#if INI_STOP_ON_FIRST_ERROR
if (error)
break;
#endif
}
#if !INI_USE_STACK
free(line);
#endif
return error;
}
/* See documentation in header file. */
inline int ini_parse_file(FILE* file, ini_handler handler, void* user)
{
return ini_parse_stream((ini_reader)fgets, file, handler, user);
}
/* See documentation in header file. */
inline int ini_parse_message(const std::string& message, ini_handler handler, void* user)
{
std::istringstream stream(message);
return ini_parse_stream((ini_reader) [](char* str, int num, void* ptrStream) {
auto stream = (std::istringstream*) ptrStream;
stream->getline(str, num);
return !!*stream ? str : nullptr;
}, &stream, handler, user);
}
/* See documentation in header file. */
inline int ini_parse(const char* filename, ini_handler handler, void* user)
{
FILE* file;
int error;
file = fopen(filename, "r");
if (!file)
return -1;
error = ini_parse_file(file, handler, user);
fclose(file);
return error;
}
#endif /* __INI_H__ */
#ifndef __INIREADER_H__
#define __INIREADER_H__
#include <map>
#include <set>
#include <string>
// Read an INI file into easy-to-access name/value pairs. (Note that I've gone
// for simplicity here rather than speed, but it should be pretty decent.)
class INIReader
{
public:
// Empty Constructor
INIReader() {};
// Construct INIReader and parse given filename. See ini.h for more info
// about the parsing.
INIReader(std::string filename, bool raw = false);
// Return the result of ini_parse(), i.e., 0 on success, line number of
// first error on parse error, or -1 on file open error.
int ParseError() const;
// Return the list of sections found in ini file
std::set<std::string> Sections();
// Get a string value from INI file, returning default_value if not found.
std::string Get(std::string section, std::string name,
std::string default_value);
// Get an integer (long) value from INI file, returning default_value if
// not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2").
long GetInteger(std::string section, std::string name, long default_value);
// Get a real (floating point double) value from INI file, returning
// default_value if not found or not a valid floating point value
// according to strtod().
double GetReal(std::string section, std::string name, double default_value);
// Get a boolean value from INI file, returning default_value if not found or if
// not a valid true/false value. Valid true values are "true", "yes", "on", "1",
// and valid false values are "false", "no", "off", "0" (not case sensitive).
bool GetBoolean(std::string section, std::string name, bool default_value);
private:
int _error;
std::map<std::string, std::string> _values;
std::set<std::string> _sections;
static std::string MakeKey(std::string section, std::string name);
static int ValueHandler(void* user, const char* section, const char* name,
const char* value);
};
#endif // __INIREADER_H__
#ifndef __INIREADER__
#define __INIREADER__
#include <algorithm>
#include <cctype>
#include <cstdlib>
using std::string;
inline INIReader::INIReader(string data, bool raw)
{
if(raw)
_error = ini_parse_message(data, ValueHandler, this);
else
_error = ini_parse(data.c_str(), ValueHandler, this);
}
inline int INIReader::ParseError() const
{
return _error;
}
inline std::set<string> INIReader::Sections()
{
return _sections;
}
inline string INIReader::Get(string section, string name, string default_value)
{
string key = MakeKey(section, name);
return _values.count(key) ? _values[key] : default_value;
}
inline long INIReader::GetInteger(string section, string name, long default_value)
{
string valstr = Get(section, name, "");
const char* value = valstr.c_str();
char* end;
// This parses "1234" (decimal) and also "0x4D2" (hex)
long n = strtol(value, &end, 0);
return end > value ? n : default_value;
}
inline double INIReader::GetReal(string section, string name, double default_value)
{
string valstr = Get(section, name, "");
const char* value = valstr.c_str();
char* end;
double n = strtod(value, &end);
return end > value ? n : default_value;
}
inline bool INIReader::GetBoolean(string section, string name, bool default_value)
{
string valstr = Get(section, name, "");
// Convert to lower case to make string comparisons case-insensitive
std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower);
if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1")
return true;
else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0")
return false;
else
return default_value;
}
inline string INIReader::MakeKey(string section, string name)
{
string key = section + "=" + name;
// Convert to lower case to make section/name lookups case-insensitive
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
return key;
}
inline int INIReader::ValueHandler(void* user, const char* section, const char* name,
const char* value)
{
INIReader* reader = (INIReader*)user;
string key = MakeKey(section, name);
if (reader->_values[key].size() > 0)
reader->_values[key] += "\n";
reader->_values[key] += value;
reader->_sections.insert(section);
return 1;
}
#endif // __INIREADER__

283
asm/identity/Identity.cpp Normal file
View File

@ -0,0 +1,283 @@
#include "Identity.h"
#include <iostream>
#include "base64.h"
#define SHA_DIGEST_LENGTH 20
#define ECC_TYPE_INDEX 5
static const char *TSKEY =
"b9dfaa7bee6ac57ac7b65f1094a1c155"
"e747327bc2fe5d51c512023fe54a2802"
"01004e90ad1daaae1075d53b7d571c30"
"e063b5a62a4a017bb394833aa0983e6e";
using namespace std;
inline int SHA1(const char* input, size_t length, char* result) {
hash_state ctx = {};
if (sha1_init(&ctx) != CRYPT_OK)
{ return -1; }
if (sha1_process(&ctx, (uint8_t*) input, length) != CRYPT_OK)
{ return -1; }
if (sha1_done(&ctx, (uint8_t*) result) != CRYPT_OK)
{ return -1; }
return 0;
}
static int decriptIdentity(char *data, uint32_t length) {
int dataSize = std::min((uint32_t) 100, length);
for (int i = 0; i < dataSize; i++) {
data[i] ^= TSKEY[i];
}
char hash[SHA_DIGEST_LENGTH];
//if(SHA1(data + 20, strlen(data + 20), hash) < 0) return -1;
hash_state ctx = {};
if (sha1_init(&ctx) != CRYPT_OK)
{ return -1; }
if (sha1_process(&ctx, (uint8_t*)data + 20, strlen(data + 20)) != CRYPT_OK)
{ return -1; }
if (sha1_done(&ctx, (uint8_t*)hash) != CRYPT_OK)
{ return -1; }
for (int i = 0; i < 20; i++) {
data[i] ^= hash[i];
}
return 0;
}
static int encriptIdentity(char *data, uint32_t length) {
char hash[SHA_DIGEST_LENGTH];
//if(SHA1(data, length, hash) < 0) return -1;
hash_state ctx;
if (sha1_init(&ctx) != CRYPT_OK)
{ return -1; }
if (sha1_process(&ctx, (uint8_t*)data + 20, strlen(data + 20)) != CRYPT_OK)
{ return -1; }
if (sha1_done(&ctx, (uint8_t*)hash) != CRYPT_OK)
{ return -1; }
for (int i = 0; i < 20; i++) {
data[i] ^= hash[i];
}
int dataSize = std::min((uint32_t) 100, length);
for (int i = 0; i < dataSize; i++) {
data[i] ^= TSKEY[i];
}
return 0;
}
namespace ts {
Identity* Identity::createNew() {
auto result = new Identity();
prng_state rndState = {};
memset(&rndState, 0, sizeof(prng_state));
int err;
result->keyPair = new ecc_key;
//cout << " -> " << find_prng("sprng") << endl;
if((err = ecc_make_key_ex(&rndState, find_prng("sprng"), result->keyPair, &ltc_ecc_sets[ECC_TYPE_INDEX])) != CRYPT_OK){
printf("Cant create a new identity (Keygen)\n");
printf("Message: %s\n", error_to_string(err));
delete result;
return nullptr;
}
return result;
}
Identity* Identity::parse(const std::string& data, std::string& error) {
int vindex = data.find('V');
if(vindex <= 0) {
error = "Invalid structure";
return nullptr;
}
auto slevel = data.substr(0, vindex);
if(slevel.find_first_not_of("0123456789") != std::string::npos) {
error = "Invalid offset (" + slevel + ")";
return nullptr;
}
mp_int keyOffset{};
mp_init(&keyOffset);
mp_read_radix(&keyOffset, slevel.data(), 10);
auto keyData = data.substr(vindex + 1);
keyData = base64::decode(keyData);
if(encriptIdentity(&keyData[0], keyData.length()) < 0) {
error = "Could not decrypt key";
return nullptr;
}
auto identity = new Identity(base64::decode(keyData), keyOffset, keyOffset);
if(!identity->keyPair) {
error = "Could not load key";
delete identity;
return nullptr;
}
printf("X: %s | %s\n", slevel.c_str(), identity->lastValidKeyOffsetString().c_str());
return identity;
}
Identity::Identity(const std::string& asnStruct, mp_int keyOffset, mp_int lastCheckedOffset) {
this->keyOffset = keyOffset;
this->lastCheckedOffset = lastCheckedOffset;
importKey(asnStruct);
mp_init_copy(&this->keyOffset, &keyOffset);
mp_init_copy(&this->lastCheckedOffset, &lastCheckedOffset);
}
Identity::Identity() {
mp_init_multi(&this->keyOffset, &this->lastCheckedOffset, nullptr);
this->keyPair = nullptr;
}
Identity::~Identity() {
delete this->keyPair;
this->keyPair = nullptr;
mp_clear_multi(&this->keyOffset, &this->lastCheckedOffset, nullptr);
}
void Identity::importKey(std::string asnStruct) {
this->keyPair = new ecc_key;
int err;
if((err = ecc_import_ex((const unsigned char *) asnStruct.data(), asnStruct.length(), this->keyPair, &ltc_ecc_sets[ECC_TYPE_INDEX])) != CRYPT_OK){
delete this->keyPair;
this->keyPair = nullptr;
printf("Cant import identity from asn structure\n");
printf("Message: %s\n", error_to_string(err));
return;
}
}
std::string Identity::exportIdentity() {
std::string data = privateKey();
decriptIdentity((char *) data.data(), data.length());
return this->lastValidKeyOffsetString() + "V" + base64_encode(data);
}
std::string Identity::uid() {
char buffer[SHA_DIGEST_LENGTH];
auto key = this->publicKey();
SHA1(key.data(), key.length(), buffer);
return base64::encode(buffer, SHA_DIGEST_LENGTH);
}
inline string hex(string input, char beg, char end){
assert(end - beg == 16);
int len = input.length() * 2;
char output[len];
int idx = 0;
for(int index = 0; index < input.length(); index++){
char elm = input[index];
output[idx++] = static_cast<char>(beg + ((elm >> 4) & 0x0F));
output[idx++] = static_cast<char>(beg + ((elm & 0x0F) >> 0));
}
return string(output, len);
}
std::string Identity::avatarId() {
return hex(base64::decode(this->uid()), 'a', 'q');
}
std::string Identity::publicKey() {
assert(this->keyPair);
ulong32 bufferLength = 1028;
char buffer[bufferLength];
ecc_export((unsigned char *) buffer, &bufferLength, PK_PUBLIC, this->keyPair);
return base64_encode(std::string(buffer, bufferLength));
}
std::string Identity::privateKey() {
assert(this->keyPair);
ulong32 bufferLength = 1028;
char buffer[bufferLength];
ecc_export((unsigned char *) buffer, &bufferLength, PK_PRIVATE, this->keyPair);
return base64_encode(std::string(buffer, bufferLength));
}
ecc_key& Identity::getPrivateKey() {
return *keyPair;
}
#define MaxUlongString 20
bool Identity::improveSecurityLevel(int target) {
auto publicKey = this->publicKey();
char hashBuffer[publicKey.length() + MaxUlongString];
memcpy(hashBuffer, publicKey.data(), publicKey.length());
if(mp_cmp(&this->lastCheckedOffset, &this->keyOffset) < 0)
mp_copy(&this->keyOffset, &this->lastCheckedOffset);
int best = getSecurityLevel(hashBuffer, publicKey.length(), this->lastCheckedOffset);
while(true){
if(best >= target) return true;
int currentLevel = getSecurityLevel(hashBuffer, publicKey.length(), this->lastCheckedOffset);
if(currentLevel >= best){
this->keyOffset = this->lastCheckedOffset;
best = currentLevel;
}
mp_add_d(&this->lastCheckedOffset, 1, &this->lastCheckedOffset);
}
}
int Identity::getSecurityLevel() {
auto length = publicKey().length();
char hashBuffer[length + MaxUlongString];
auto publicKey = this->publicKey();
memcpy(hashBuffer, publicKey.data(), publicKey.length());
return getSecurityLevel(hashBuffer, publicKey.length(), this->keyOffset);
}
int Identity::getSecurityLevel(char *hashBuffer, size_t keyLength, mp_int offset) {
char numBuffer[MaxUlongString];
mp_todecimal(&offset, numBuffer);
/*
int numLen = 0;
do {
numBuffer[numLen] = '0' + (offset % 10);
offset /= 10;
numLen++;
} while(offset > 0);
for(int i = 0; i < numLen; i++)
hashBuffer[keyLength + i] = numBuffer[numLen - (i + 1)];
*/
auto numLen = strlen(numBuffer);
memcpy(&hashBuffer[keyLength], numBuffer, numLen);
char shaBuffer[SHA_DIGEST_LENGTH];
SHA1(hashBuffer, keyLength + numLen, shaBuffer);
//Leading zero bits
int zeroBits = 0;
int i;
for(i = 0; i < SHA_DIGEST_LENGTH; i++)
if(shaBuffer[i] == 0) zeroBits += 8;
else break;
if(i < SHA_DIGEST_LENGTH)
for(int bit = 0; bit < 8; bit++)
if((shaBuffer[i] & (1 << bit)) == 0) zeroBits++;
else break;
return zeroBits;
}
}

59
asm/identity/Identity.h Normal file
View File

@ -0,0 +1,59 @@
#pragma once
#include <tomcrypt.h>
#include <string>
#include <tommath.h>
namespace ts {
class Identity {
inline std::string toString(const mp_int& num) {
char buffer[1024];
mp_todecimal(&num, buffer);
return std::string(buffer);
}
public:
static Identity* createNew();
static Identity* parse(const std::string&, std::string&);
Identity(const std::string& asnStruct,mp_int keyOffset,mp_int lastCheckedOffset);
~Identity();
bool valid(){ return keyPair != nullptr; }
std::string uid();
std::string avatarId();
std::string publicKey();
std::string privateKey();
std::string exportIdentity();
ecc_key* getKeyPair(){
return keyPair;
}
ecc_key& getPrivateKey();
bool improveSecurityLevel(int target);
int getSecurityLevel();
mp_int lastValidKeyOffset(){ return keyOffset; }
mp_int lastTestedKeyOffset(){ return lastCheckedOffset; }
std::string lastValidKeyOffsetString(){
return toString(this->lastValidKeyOffset());
}
std::string lastTestedKeyOffsetString(){
return toString(this->lastTestedKeyOffset());
}
private:
Identity();
int getSecurityLevel(char* hasBuffer, size_t keyLength, mp_int offset);
void importKey(std::string asn1);
ecc_key* keyPair = nullptr;
mp_int keyOffset;
mp_int lastCheckedOffset;
};
}

View File

@ -0,0 +1,136 @@
#include <cstdio>
#include <emscripten.h>
#include <emscripten/bind.h>
#include <tomcrypt.h>
#include <cmath>
#include <iostream>
#include "Identity.h"
#include "base64.h"
#define INI_MAX_LINE 1024
#include "INIReader.h"
using namespace emscripten;
using namespace std;
extern "C" {
std::string errorMessage = "";
inline const char* cstr(const std::string& message) {
auto buffer = (char*) malloc(message.length() + 1);
cout << "Allocating at " << (void*) buffer << endl;
buffer[message.length()] = '\0';
memcpy(buffer, message.data(), message.length());
return buffer;
}
EMSCRIPTEN_KEEPALIVE
const char* last_error_message() {
return cstr(errorMessage);
};
EMSCRIPTEN_KEEPALIVE
void destroy_string(const char* str) {
cout << "Deallocating at " << (void*) str << endl;
if(str) free((void *) str);
};
inline void clear_error() { errorMessage = ""; }
EMSCRIPTEN_KEEPALIVE
int tomcrypt_initialize() {
init_LTM();
if(register_prng(&sprng_desc) == -1) {
printf("could not setup prng\n");
return EXIT_FAILURE;
}
if (register_cipher(&rijndael_desc) == -1) {
printf("could not setup rijndael\n");
return EXIT_FAILURE;
}
cout << "Initialized!" << endl;
return 0;
}
EMSCRIPTEN_KEEPALIVE
void* parse_identity(const char* input) {
cout << "Got messsage: " << input << endl;
clear_error();
return ts::Identity::parse(input, errorMessage);
}
EMSCRIPTEN_KEEPALIVE
void* parse_identity_file(const char* input) {
clear_error();
INIReader reader(input, true);
if(reader.ParseError() != 0) {
errorMessage = "Could not parse file " + to_string(reader.ParseError());
return nullptr;
}
auto identity = reader.Get("Identity", "identity", "");
if(!identity.empty() && identity[0] == '"')
identity = identity.substr(1);
if(!identity.empty() && identity.back() == '"')
identity = identity.substr(0, identity.length() - 1);
if(identity.empty()) {
errorMessage = "Mussing identity value at Identity::identity";
return nullptr;
}
return ts::Identity::parse(identity, errorMessage);
}
#define IDENTITIEFY(_ret) \
auto identity = dynamic_cast<ts::Identity*>((ts::Identity*) ptrIdentity); \
if(!identity) { \
errorMessage = "Invalid identity pointer!"; \
return _ret; \
}
EMSCRIPTEN_KEEPALIVE
void delete_identity(void* ptrIdentity) {
IDENTITIEFY(;);
delete identity;
}
EMSCRIPTEN_KEEPALIVE
const char* identity_security_level(void* ptrIdentity) {
IDENTITIEFY("");
return cstr(std::to_string(identity->getSecurityLevel()));
}
EMSCRIPTEN_KEEPALIVE
const char* identity_export(void* ptrIdentity) {
IDENTITIEFY("");
return cstr(identity->exportIdentity());
}
EMSCRIPTEN_KEEPALIVE
const char* identity_key_public(void* ptrIdentity) {
IDENTITIEFY("");
return cstr(identity->publicKey());
}
EMSCRIPTEN_KEEPALIVE
const char* identity_uid(void* ptrIdentity) {
IDENTITIEFY("");
return cstr(identity->uid());
}
EMSCRIPTEN_KEEPALIVE
const char* identity_sign(void* ptrIdentity, const char* message, int length) {
IDENTITIEFY("");
ulong32 bufferLength = 128;
char signBuffer[bufferLength];
prng_state rndState = {};
memset(&rndState, 0, sizeof(prng_state));
auto state = ecc_sign_hash((const unsigned char*) message, length, reinterpret_cast<unsigned char *>(signBuffer), &bufferLength, &rndState, find_prng("sprng"), identity->getKeyPair());
if(state != CRYPT_OK) {
errorMessage = "Could not sign message (" + std::string(error_to_string(state)) + "|" + std::to_string(state) + ")";
return "";
}
return cstr(base64::encode(signBuffer, bufferLength));
}
}

59
asm/identity/base64.h Normal file
View File

@ -0,0 +1,59 @@
#pragma once
#include <string>
#include <tomcrypt.h>
#include <iostream>
namespace base64 {
/**
* Encodes a given string in Base64
* @param input The input string to Base64-encode
* @param inputSize The size of the input to decode
* @return A Base64-encoded version of the encoded string
*/
inline std::string encode(const char* input, const unsigned long inputSize) {
auto outlen = static_cast<unsigned long>(inputSize + (inputSize / 3.0) + 16);
auto outbuf = new unsigned char[outlen]; //Reserve output memory
if(base64_encode((unsigned char*) input, inputSize, outbuf, &outlen) != CRYPT_OK){
std::cerr << "Invalid input '" << input << "'" << std::endl;
return "";
}
std::string ret((char*) outbuf, outlen);
delete[] outbuf;
return ret;
}
/**
* Encodes a given string in Base64
* @param input The input string to Base64-encode
* @return A Base64-encoded version of the encoded string
*/
inline std::string encode(const std::string& input) { return encode(input.c_str(), input.size()); }
/**
* Decodes a Base64-encoded string.
* @param input The input string to decode
* @return A string (binary) that represents the Base64-decoded data of the input
*/
inline std::string decode(const char* input, ulong32 size) {
auto out = new unsigned char[size];
if(base64_strict_decode((unsigned char*) input, size, out, &size) != CRYPT_OK){
std::cerr << "Invalid base 64 string '" << input << "'" << std::endl;
return "";
}
std::string ret((char*) out, size);
delete[] out;
return ret;
}
/**
* Decodes a Base64-encoded string.
* @param input The input string to decode
* @return A string (binary) that represents the Base64-decoded data of the input
*/
inline std::string decode(const std::string& input) { return decode(input.c_str(), input.size()); }
}
inline std::string base64_encode(const char* input, const unsigned long inputSize) { return base64::encode(input, inputSize); }
inline std::string base64_encode(const std::string& input) { return base64::encode(input.c_str(), input.size()); }

1
asm/libraries/opus Submodule

@ -0,0 +1 @@
Subproject commit b97dd67fdc75a39d0fc99ceee573921ba3e73b1f

@ -0,0 +1 @@
Subproject commit bc6d70bd1f4a6778cf51379090d8391dcf53590d

1
asm/libraries/tommath Submodule

@ -0,0 +1 @@
Subproject commit fe6cc64884b2b408b607389f46266d44fd942a79

132
asm/src/opus.cpp Normal file
View File

@ -0,0 +1,132 @@
#include <opus.h>
#include <emscripten.h>
#include <string>
using namespace std;
extern "C" {
struct OpusHandle {
OpusEncoder* encoder = nullptr;
OpusDecoder* decoder = nullptr;
size_t channelCount = 1;
size_t sampleRate = 48000;
int opusType = OPUS_APPLICATION_AUDIO;
};
const char* opus_errors[7] = {
"One or more invalid/out of range arguments", //-1 (OPUS_BAD_ARG)
"Not enough bytes allocated in the buffer", //-2 (OPUS_BUFFER_TOO_SMALL)
"An internal error was detected", //-3 (OPUS_INTERNAL_ERROR)
"The compressed data passed is corrupted", //-4 (OPUS_INVALID_PACKET)
"Invalid/unsupported request number", //-5 (OPUS_UNIMPLEMENTED)
"An encoder or decoder structure is invalid or already freed", //-6 (OPUS_INVALID_STATE)
"Memory allocation has failed" //-7 (OPUS_ALLOC_FAIL)
};
inline const char* opus_error_message(int error) {
error = abs(error);
if(error > 0 && error <= 7) return opus_errors[error - 1];
return "undefined error";
}
inline int currentMillies() {
return EM_ASM_INT({ return Date.now(); });
}
#define _S(x) #x
#define INVOKE_OPUS(result, method, ...) \
result = method( __VA_ARGS__ ); \
if(error != 0){ \
printf("Got opus error while invoking %s. Code: %d Message: %s\n", _S(method), error, opus_error_message(error)); \
return false; \
}
inline bool reinitialize_decoder(OpusHandle *handle) {
if (handle->decoder)
opus_decoder_destroy(handle->decoder);
int error = 0;
INVOKE_OPUS(handle->decoder, opus_decoder_create, 48000, handle->channelCount, &error);
return true;
}
inline bool reinitialize_encoder(OpusHandle *handle) {
if (handle->encoder)
opus_encoder_destroy(handle->encoder);
int error = 0;
INVOKE_OPUS(handle->encoder, opus_encoder_create, 48000, handle->channelCount, handle->opusType, &error);
INVOKE_OPUS(error, opus_encoder_ctl, handle->encoder, OPUS_SET_COMPLEXITY(1));
//INVOKE_OPUS(error, opus_encoder_ctl, handle->encoder, OPUS_SET_BITRATE(4740));
EM_ASM(
printMessageToServerTab('Encoder initialized!');
printMessageToServerTab(' Comprexity: 1');
printMessageToServerTab(' Bitrate: 4740');
);
return true;
}
EMSCRIPTEN_KEEPALIVE
OpusHandle* codec_opus_createNativeHandle(size_t channelCount, int type) {
printf("Initialize opus. (Channel count: %d Sample rate: %d Type: %d)!\n", channelCount, 48000, type);
auto codec = new OpusHandle{};
codec->opusType = type;
if(!reinitialize_decoder(codec)) return nullptr;
if(!reinitialize_encoder(codec)) return nullptr;
return codec;
}
EMSCRIPTEN_KEEPALIVE
void codec_opus_deleteNativeHandle(OpusHandle* codec) {
if(!codec) return;
if(codec->decoder) opus_decoder_destroy(codec->decoder);
codec->decoder = nullptr;
if(codec->encoder) opus_encoder_destroy(codec->encoder);
codec->encoder = nullptr;
delete codec;
}
EMSCRIPTEN_KEEPALIVE
int codec_opus_encode(OpusHandle* handle, uint8_t* buffer, size_t length, size_t maxLength) {
auto begin = currentMillies();
auto result = opus_encode_float(handle->encoder, (float*) buffer, length / handle->channelCount, buffer, maxLength);
if(result < 0) return result;
auto end = currentMillies();
EM_ASM({
printMessageToServerTab("codec_opus_encode(...) tooks " + $0 + "ms to execute!");
}, end - begin);
return result;
}
EMSCRIPTEN_KEEPALIVE
int codec_opus_decode(OpusHandle* handle, uint8_t* buffer, size_t length, size_t maxLength) {
auto result = opus_decode_float(handle->decoder, buffer, length, (float*) buffer, maxLength / sizeof(float) / handle->channelCount, false);
if(result < 0) return result; //Failed
return result;
}
EMSCRIPTEN_KEEPALIVE
int codec_opus_changeApplication(OpusHandle* handle, int type) {
handle->opusType = type;
if(type != OPUS_APPLICATION_VOIP && type != OPUS_APPLICATION_AUDIO && type != OPUS_APPLICATION_RESTRICTED_LOWDELAY)
return 1;
return opus_encoder_ctl(handle->encoder, OPUS_SET_APPLICATION(type));
}
EMSCRIPTEN_KEEPALIVE
int codec_opus_reset(OpusHandle* handle) {
if(!reinitialize_decoder(handle)) return 0;
if(!reinitialize_encoder(handle)) return 0;
return 1;
}
/*
opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));
opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type));
*/
}