yipee data cards are done
This commit is contained in:
@@ -80,7 +80,6 @@ local function sandboxValue(val)
|
|||||||
return nt
|
return nt
|
||||||
end
|
end
|
||||||
if type(val) == "userdata" then
|
if type(val) == "userdata" then
|
||||||
-- Light userdata shall never escape our shi!
|
|
||||||
-- This matches how OC wraps it
|
-- This matches how OC wraps it
|
||||||
-- TODO: just make our own shi with fields and stuff
|
-- TODO: just make our own shi with fields and stuff
|
||||||
-- like a component proxy, because this sucks
|
-- like a component proxy, because this sucks
|
||||||
@@ -90,7 +89,7 @@ local function sandboxValue(val)
|
|||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
local wrapped = {type = "userdata"}
|
local wrapped = {type = "userdata", userdata = val}
|
||||||
for name, m in pairs(userdata.methods(val)) do
|
for name, m in pairs(userdata.methods(val)) do
|
||||||
wrapped[name] = {
|
wrapped[name] = {
|
||||||
name = 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);
|
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");
|
if(C) nn_setError(C, "ne: data method not implemented");
|
||||||
return NN_EBADCALL;
|
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) {
|
static nn_Exit nn_dataHandler(nn_ComponentRequest *req) {
|
||||||
nn_Context *ctx = req->ctx;
|
nn_Context *ctx = req->ctx;
|
||||||
nn_DataState *state = req->classState;
|
nn_DataState *state = req->classState;
|
||||||
@@ -6360,26 +6353,22 @@ static nn_Exit nn_dataHandler(nn_ComponentRequest *req) {
|
|||||||
|
|
||||||
if(user->action == NN_USER_SERIALIZE) {
|
if(user->action == NN_USER_SERIALIZE) {
|
||||||
// its assumed bytelen is not ridiculous
|
// its assumed bytelen is not ridiculous
|
||||||
size_t serlen = 2 + key->bytelen;
|
size_t serlen = 1 + key->bytelen;
|
||||||
NN_VLA(unsigned char, ser, serlen);
|
NN_VLA(unsigned char, ser, serlen);
|
||||||
unsigned short bitsAndPub = (key->bitlen * 2) + (key->isPublic ? 1 : 0);
|
ser[0] = key->isPublic ? 1 : 0;
|
||||||
ser[0] = (bitsAndPub >> 0) & 0xFF;
|
nn_memcpy(ser + 1, key->bytes, key->bytelen);
|
||||||
ser[1] = (bitsAndPub >> 8) & 0xFF;
|
|
||||||
nn_memcpy(ser + 2, key->bytes, key->bytelen);
|
|
||||||
return nn_pushlstring(C, (const char *)ser, serlen);
|
return nn_pushlstring(C, (const char *)ser, serlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(user->action == NN_USER_DESERIALIZE) {
|
if(user->action == NN_USER_DESERIALIZE) {
|
||||||
size_t serlen = user->deserialize.len;
|
size_t serlen = user->deserialize.len;
|
||||||
const unsigned char *ser = (const unsigned char *)user->deserialize.data;
|
const unsigned char *ser = (const unsigned char *)user->deserialize.data;
|
||||||
size_t bytelen = serlen - 2;
|
size_t bytelen = serlen - 1;
|
||||||
unsigned short bitsAndPub = ((unsigned short)ser[0]) + (((unsigned short)ser[1]) << 8);
|
|
||||||
key = nn_alloc(ctx, sizeof(*key) + bytelen);
|
key = nn_alloc(ctx, sizeof(*key) + bytelen);
|
||||||
if(key == NULL) return NN_ENOMEM;
|
if(key == NULL) return NN_ENOMEM;
|
||||||
key->isPublic = (bitsAndPub&1) != 0;
|
key->isPublic = ser[0] != 0;
|
||||||
key->bitlen = bitsAndPub/2;
|
|
||||||
key->bytelen = bytelen;
|
key->bytelen = bytelen;
|
||||||
nn_memcpy(key->bytes, ser + 2, key->bytelen);
|
nn_memcpy(key->bytes, ser + 1, key->bytelen);
|
||||||
user->state = key;
|
user->state = key;
|
||||||
return NN_OK;
|
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)");
|
nn_setError(C, "invalid bit length (only 256-bit and 384-bit are supported)");
|
||||||
return NN_EBADCALL;
|
return NN_EBADCALL;
|
||||||
}
|
}
|
||||||
// TODO: this is test code, no OOM check. Implement the correct version and make sure it handles OOMs correctly
|
dreq.action = NN_DATA_GENKEYS;
|
||||||
size_t keylen = bitLen / 8;
|
dreq.genkeybitsize = bitLen;
|
||||||
nn_DataKey *key = nn_alloc(ctx, sizeof(*key) + keylen);
|
|
||||||
key->isPublic = true;
|
e = state->handler(&dreq);
|
||||||
key->bitlen = bitLen;
|
if(e) return e;
|
||||||
key->bytelen = keylen;
|
|
||||||
nn_memset(key->bytes, 'A', key->bytelen);
|
// 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;
|
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");
|
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.
|
// Generate an ECDH public/private pair of either 256 or 384 bits each.
|
||||||
NN_DATA_GENKEYS,
|
NN_DATA_GENKEYS,
|
||||||
|
|
||||||
|
// validate key, cuz we feel like it
|
||||||
|
NN_DATA_VALIDATEKEY,
|
||||||
|
|
||||||
// Does an ECDH pass, matching javax.crypto.KeyAgreement.
|
// Does an ECDH pass, matching javax.crypto.KeyAgreement.
|
||||||
// This generates a shared secret as binary data.
|
// 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
|
// 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_DATA_ECDSA_VERIFY,
|
||||||
} nn_DataCardAction;
|
} 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 {
|
typedef struct nn_DataCardRequest {
|
||||||
nn_Context *ctx;
|
nn_Context *ctx;
|
||||||
nn_Computer *computer;
|
nn_Computer *computer;
|
||||||
@@ -1860,6 +1870,30 @@ typedef struct nn_DataCardRequest {
|
|||||||
const char *data;
|
const char *data;
|
||||||
size_t datalen;
|
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;
|
} nn_DataCardRequest;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user