yipee data cards are done
This commit is contained in:
@@ -80,7 +80,6 @@ local function sandboxValue(val)
|
||||
return nt
|
||||
end
|
||||
if type(val) == "userdata" then
|
||||
-- Light userdata shall never escape our shi!
|
||||
-- This matches how OC wraps it
|
||||
-- TODO: just make our own shi with fields and stuff
|
||||
-- like a component proxy, because this sucks
|
||||
@@ -90,7 +89,7 @@ local function sandboxValue(val)
|
||||
end,
|
||||
}
|
||||
|
||||
local wrapped = {type = "userdata"}
|
||||
local wrapped = {type = "userdata", userdata = val}
|
||||
for name, m in pairs(userdata.methods(val)) do
|
||||
wrapped[name] = {
|
||||
name = name,
|
||||
|
||||
26
src/main.c
26
src/main.c
@@ -123,6 +123,32 @@ static nn_Exit ne_dataBullshit(nn_DataCardRequest *req) {
|
||||
return nn_pushlstring(C, req->data, req->datalen);
|
||||
}
|
||||
|
||||
if(action == NN_DATA_VALIDATEKEY) {
|
||||
// its valid, trust
|
||||
return NN_OK;
|
||||
}
|
||||
|
||||
if(action == NN_DATA_GENKEYS) {
|
||||
char a = 'A' + rand() % 26;
|
||||
char b = 'A' + rand() % 26;
|
||||
nn_pushlstring(C, &a, 1);
|
||||
return nn_pushlstring(C, &b, 1);
|
||||
}
|
||||
|
||||
if(action == NN_DATA_ECDH) {
|
||||
char buf[32];
|
||||
memset(buf, 'e', 32);
|
||||
return nn_pushlstring(C, buf, 32);
|
||||
}
|
||||
|
||||
if(action == NN_DATA_ECDSA_SIGN) {
|
||||
return nn_pushstring(C, "epic signature bro");
|
||||
}
|
||||
if(action == NN_DATA_ECDSA_VERIFY) {
|
||||
req->checksig.sigpassed = strcmp(req->checksig.signature, "epic signature bro");
|
||||
return NN_OK;
|
||||
}
|
||||
|
||||
if(C) nn_setError(C, "ne: data method not implemented");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
|
||||
199
src/neonucleus.c
199
src/neonucleus.c
@@ -6318,13 +6318,6 @@ nn_DataCard nn_defaultDataCards[3] = {
|
||||
},
|
||||
};
|
||||
|
||||
typedef struct nn_DataKey {
|
||||
bool isPublic;
|
||||
unsigned short bitlen;
|
||||
size_t bytelen;
|
||||
char bytes[];
|
||||
} nn_DataKey;
|
||||
|
||||
static nn_Exit nn_dataHandler(nn_ComponentRequest *req) {
|
||||
nn_Context *ctx = req->ctx;
|
||||
nn_DataState *state = req->classState;
|
||||
@@ -6360,26 +6353,22 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) {
|
||||
|
||||
if(user->action == NN_USER_SERIALIZE) {
|
||||
// its assumed bytelen is not ridiculous
|
||||
size_t serlen = 2 + key->bytelen;
|
||||
size_t serlen = 1 + key->bytelen;
|
||||
NN_VLA(unsigned char, ser, serlen);
|
||||
unsigned short bitsAndPub = (key->bitlen * 2) + (key->isPublic ? 1 : 0);
|
||||
ser[0] = (bitsAndPub >> 0) & 0xFF;
|
||||
ser[1] = (bitsAndPub >> 8) & 0xFF;
|
||||
nn_memcpy(ser + 2, key->bytes, key->bytelen);
|
||||
ser[0] = key->isPublic ? 1 : 0;
|
||||
nn_memcpy(ser + 1, key->bytes, key->bytelen);
|
||||
return nn_pushlstring(C, (const char *)ser, serlen);
|
||||
}
|
||||
|
||||
if(user->action == NN_USER_DESERIALIZE) {
|
||||
size_t serlen = user->deserialize.len;
|
||||
const unsigned char *ser = (const unsigned char *)user->deserialize.data;
|
||||
size_t bytelen = serlen - 2;
|
||||
unsigned short bitsAndPub = ((unsigned short)ser[0]) + (((unsigned short)ser[1]) << 8);
|
||||
size_t bytelen = serlen - 1;
|
||||
key = nn_alloc(ctx, sizeof(*key) + bytelen);
|
||||
if(key == NULL) return NN_ENOMEM;
|
||||
key->isPublic = (bitsAndPub&1) != 0;
|
||||
key->bitlen = bitsAndPub/2;
|
||||
key->isPublic = ser[0] != 0;
|
||||
key->bytelen = bytelen;
|
||||
nn_memcpy(key->bytes, ser + 2, key->bytelen);
|
||||
nn_memcpy(key->bytes, ser + 1, key->bytelen);
|
||||
user->state = key;
|
||||
return NN_OK;
|
||||
}
|
||||
@@ -6618,15 +6607,175 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) {
|
||||
nn_setError(C, "invalid bit length (only 256-bit and 384-bit are supported)");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
// TODO: this is test code, no OOM check. Implement the correct version and make sure it handles OOMs correctly
|
||||
size_t keylen = bitLen / 8;
|
||||
nn_DataKey *key = nn_alloc(ctx, sizeof(*key) + keylen);
|
||||
key->isPublic = true;
|
||||
key->bitlen = bitLen;
|
||||
key->bytelen = keylen;
|
||||
nn_memset(key->bytes, 'A', key->bytelen);
|
||||
dreq.action = NN_DATA_GENKEYS;
|
||||
dreq.genkeybitsize = bitLen;
|
||||
|
||||
e = state->handler(&dreq);
|
||||
if(e) return e;
|
||||
|
||||
// the keygen DARED succeed which means we must actually
|
||||
// create those keys smh. Darn you crypto bros!
|
||||
|
||||
size_t pubIdx = nn_getstacksize(C) - 2;
|
||||
|
||||
size_t publen = 0, privlen = 0;
|
||||
int pubUser = -1, privUser = -1;
|
||||
nn_DataKey *pubKey = NULL, *privKey = NULL;
|
||||
|
||||
const char *pubdata = nn_tolstring(C, pubIdx, &publen);
|
||||
const char *privdata = nn_tolstring(C, pubIdx + 1, &privlen);
|
||||
|
||||
pubKey = nn_alloc(ctx, sizeof(nn_DataKey) + publen);
|
||||
if(pubKey == NULL) {
|
||||
e = NN_ENOMEM;
|
||||
goto considered_harmful;
|
||||
}
|
||||
pubKey->isPublic = true;
|
||||
pubKey->bytelen = publen;
|
||||
nn_memcpy(pubKey->bytes, pubdata, publen);
|
||||
|
||||
privKey = nn_alloc(ctx, sizeof(nn_DataKey) + privlen);
|
||||
if(privKey == NULL) {
|
||||
e = NN_ENOMEM;
|
||||
goto considered_harmful;
|
||||
}
|
||||
privKey->isPublic = false;
|
||||
privKey->bytelen = privlen;
|
||||
nn_memcpy(privKey->bytes, privdata, privlen);
|
||||
|
||||
pubUser = nn_allocUserdata(C, pubKey, req->compAddress);
|
||||
if(pubUser < 0) {
|
||||
e = NN_ELIMIT;
|
||||
goto considered_harmful;
|
||||
}
|
||||
|
||||
privUser = nn_allocUserdata(C, privKey, req->compAddress);
|
||||
if(privUser < 0) {
|
||||
e = NN_ELIMIT;
|
||||
goto considered_harmful;
|
||||
}
|
||||
|
||||
e = nn_pushuserdata(C, pubUser);
|
||||
if(e) goto considered_harmful;
|
||||
|
||||
e = nn_pushuserdata(C, privUser);
|
||||
if(e) goto considered_harmful;
|
||||
|
||||
req->returnCount = 2;
|
||||
return NN_OK;
|
||||
|
||||
considered_harmful:
|
||||
nn_free(ctx, pubKey, sizeof(*pubKey) + publen);
|
||||
nn_free(ctx, privKey, sizeof(*privKey) + privlen);
|
||||
if(pubUser >= 0) nn_freeUserdata(C, pubUser);
|
||||
if(privUser >= 0) nn_freeUserdata(C, privUser);
|
||||
return e;
|
||||
}
|
||||
|
||||
if(method == NN_DATANUM_DESERIALIZEKEY) {
|
||||
if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL;
|
||||
if(nn_checkboolean(C, 1, "bad argument #2 (boolean expected)")) return NN_EBADCALL;
|
||||
dreq.action = NN_DATA_VALIDATEKEY;
|
||||
dreq.validatekey.buf = nn_tolstring(C, 0, &dreq.validatekey.len);
|
||||
dreq.validatekey.isPublic = nn_toboolean(C, 1);
|
||||
e = state->handler(&dreq);
|
||||
if(e) return e;
|
||||
req->returnCount = 1;
|
||||
return nn_pushuserdata(C, nn_allocUserdata(C, key, req->compAddress));
|
||||
size_t keylen = dreq.validatekey.len;
|
||||
nn_DataKey *key = nn_alloc(ctx, sizeof(*key) + keylen);
|
||||
if(key == NULL) return NN_ENOMEM;
|
||||
key->isPublic = dreq.validatekey.isPublic;
|
||||
key->bytelen = keylen;
|
||||
nn_memcpy(key->bytes, dreq.validatekey.buf, key->bytelen);
|
||||
int u = nn_allocUserdata(C, key, req->compAddress);
|
||||
if(u < 0) {
|
||||
nn_free(ctx, key, sizeof(*key) + keylen);
|
||||
return NN_ELIMIT;
|
||||
}
|
||||
e = nn_pushuserdata(C, u);
|
||||
if(e) {
|
||||
nn_free(ctx, key, sizeof(*key) + keylen);
|
||||
return e;
|
||||
}
|
||||
req->returnCount = 1;
|
||||
return NN_OK;
|
||||
}
|
||||
|
||||
if(method == NN_DATANUM_ECDH) {
|
||||
if(nn_checkuserdata(C, 0, "bad argument #1 (userdata expected)")) return NN_EBADCALL;
|
||||
if(nn_checkuserdata(C, 1, "bad argument #2 (userdata expected)")) return NN_EBADCALL;
|
||||
|
||||
const nn_DataKey *privateKey = nn_unwrapUserdata(C, nn_touserdata(C, 0), req->compAddress);
|
||||
if(privateKey == NULL) {
|
||||
nn_setError(C, "invalid or foreign private key");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
const nn_DataKey *publicKey = nn_unwrapUserdata(C, nn_touserdata(C, 1), req->compAddress);
|
||||
if(publicKey == NULL) {
|
||||
nn_setError(C, "invalid or foreign public key");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
|
||||
if(privateKey->isPublic == publicKey->isPublic) {
|
||||
nn_setError(C, "illogical key pair");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
if(privateKey->isPublic) {
|
||||
const nn_DataKey *tmp = privateKey;
|
||||
privateKey = publicKey;
|
||||
publicKey = tmp;
|
||||
}
|
||||
|
||||
dreq.action = NN_DATA_ECDH;
|
||||
dreq.ecdh.privateKey = privateKey;
|
||||
dreq.ecdh.publicKey = publicKey;
|
||||
req->returnCount = 1;
|
||||
return state->handler(&dreq);
|
||||
}
|
||||
|
||||
if(method == NN_DATANUM_ECDSA) {
|
||||
if(nn_getstacksize(C) == 2) {
|
||||
// we gotta generate a signature cuz some dingus
|
||||
// wanted everyone to know it was them who wrote
|
||||
// this text smh
|
||||
if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL;
|
||||
if(nn_checkuserdata(C, 1, "bad argument #2 (userdata expected)")) return NN_EBADCALL;
|
||||
|
||||
dreq.action = NN_DATA_ECDSA_SIGN;
|
||||
dreq.sign.data = nn_tolstring(C, 0, &dreq.sign.len);
|
||||
dreq.sign.privateKey = nn_unwrapUserdata(C, nn_touserdata(C, 1), req->compAddress);
|
||||
if(dreq.sign.privateKey == NULL) {
|
||||
nn_setError(C, "invalid or foreign private key");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
if(dreq.sign.privateKey->isPublic) {
|
||||
nn_setError(C, "signatures require a private key");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
req->returnCount = 1;
|
||||
return state->handler(&dreq);
|
||||
}
|
||||
// signature verification, cuz we do not trust the author label
|
||||
if(nn_checkstring(C, 0, "bad argument #1 (string expected)")) return NN_EBADCALL;
|
||||
if(nn_checkuserdata(C, 1, "bad argument #2 (userdata expected)")) return NN_EBADCALL;
|
||||
if(nn_checkstring(C, 2, "bad argument #3 (string expected)")) return NN_EBADCALL;
|
||||
dreq.action = NN_DATA_ECDSA_VERIFY;
|
||||
dreq.checksig.data = nn_tolstring(C, 0, &dreq.checksig.datalen);
|
||||
dreq.checksig.publicKey = nn_unwrapUserdata(C, nn_touserdata(C, 1), req->compAddress);
|
||||
dreq.checksig.signature = nn_tolstring(C, 0, &dreq.checksig.siglen);
|
||||
dreq.checksig.sigpassed = false;
|
||||
if(dreq.checksig.publicKey == NULL) {
|
||||
nn_setError(C, "invalid or foreign private key");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
if(!dreq.checksig.publicKey->isPublic) {
|
||||
nn_setError(C, "validaing signatures require a public key");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
e = state->handler(&dreq);
|
||||
if(e) return e;
|
||||
req->returnCount = 1;
|
||||
return nn_pushbool(C, dreq.checksig.sigpassed);
|
||||
}
|
||||
|
||||
if(C) nn_setError(C, "data: not implemented yet");
|
||||
|
||||
@@ -1809,6 +1809,9 @@ typedef enum nn_DataCardAction {
|
||||
// Generate an ECDH public/private pair of either 256 or 384 bits each.
|
||||
NN_DATA_GENKEYS,
|
||||
|
||||
// validate key, cuz we feel like it
|
||||
NN_DATA_VALIDATEKEY,
|
||||
|
||||
// Does an ECDH pass, matching javax.crypto.KeyAgreement.
|
||||
// This generates a shared secret as binary data.
|
||||
// This is not an AES key as output, the AES key is often computed by either MD5 hashing
|
||||
@@ -1821,6 +1824,13 @@ typedef enum nn_DataCardAction {
|
||||
NN_DATA_ECDSA_VERIFY,
|
||||
} nn_DataCardAction;
|
||||
|
||||
// The representation of datacard key userdata
|
||||
typedef struct nn_DataKey {
|
||||
bool isPublic;
|
||||
unsigned short bytelen;
|
||||
char bytes[];
|
||||
} nn_DataKey;
|
||||
|
||||
typedef struct nn_DataCardRequest {
|
||||
nn_Context *ctx;
|
||||
nn_Computer *computer;
|
||||
@@ -1860,6 +1870,30 @@ typedef struct nn_DataCardRequest {
|
||||
const char *data;
|
||||
size_t datalen;
|
||||
};
|
||||
struct {
|
||||
const char *buf;
|
||||
size_t len;
|
||||
bool isPublic;
|
||||
} validatekey;
|
||||
struct {
|
||||
const nn_DataKey *publicKey;
|
||||
const nn_DataKey *privateKey;
|
||||
} ecdh;
|
||||
struct {
|
||||
const char *data;
|
||||
size_t len;
|
||||
const nn_DataKey *privateKey;
|
||||
} sign;
|
||||
struct {
|
||||
const char *data;
|
||||
size_t datalen;
|
||||
const nn_DataKey *publicKey;
|
||||
const char *signature;
|
||||
size_t siglen;
|
||||
// returns whether the signature actually passed
|
||||
bool sigpassed;
|
||||
} checksig;
|
||||
int genkeybitsize;
|
||||
};
|
||||
} nn_DataCardRequest;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user