From 1a9074c8b0360c81fb0386b23aa9f7c4bfb02273 Mon Sep 17 00:00:00 2001 From: Alexander Vdolainen Date: Sun, 26 Jun 2016 17:39:18 +0300 Subject: [PATCH] sxt: partial commit of old functions, just to make tools fine; --- sxt/ppkp_ops.c | 579 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 579 insertions(+) diff --git a/sxt/ppkp_ops.c b/sxt/ppkp_ops.c index de1adad..04847e2 100644 --- a/sxt/ppkp_ops.c +++ b/sxt/ppkp_ops.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -39,8 +40,18 @@ #include #include +#include +#include +#include #include #include +#include +#include + +/* locals */ +static int sxt_key_export_priv_ed25519(const sxtkey_t *key, const char *pass, sxtsafebuffer_t **bin); +static int sxt_public_ed25519_2sb(const sxtkey_t *key, sxtsafebuffer_t **buf); +static int sxt_public_ed25519_2rdb(const sxtkey_t *key, sxtrdb_t **out); int sxt_key_generate(sxtkey_t *key, int type, int opt) { @@ -132,3 +143,571 @@ void sxt_key_free(sxtkey_t *key) free(key); return; } + +const char *sxt_key_name(int type) +{ + switch(type) { + case PPKP_ED25519: + return "ppkp-ed25519"; + default: return NULL; + } + + return NULL; +} + +uint8_t sxt_key_type_fname(const char *name) +{ + if(!name) return 0; + + if(!strcmp(name, "ppkp-ed25519")) return PPKP_ED25519; + else return 0; +} + +int sxt_key_public(const sxtkey_t *key) +{ + if(!key) return 0; + + return (key->flags & SXT_PPKP_PUBLIC) == SXT_PPKP_PUBLIC; +} + +int sxt_key_private(const sxtkey_t *key) +{ + if(!key) return 0; + + return (key->flags & SXT_PPKP_PRIVATE) == SXT_PPKP_PRIVATE; +} + +int sxt_key_assign_hash(sxtkey_t *key, uint64_t hash) +{ + if(!key) return SXT_EINVAL; + + if(!sxt_key_private(key)) return SXT_EINVAL; + + if(key->hash) return SXT_EKEY; + else key->hash = hash; + + return SXT_SUCCESS; +} + +uint64_t sxt_key_hash(const sxtkey_t *key) +{ + if(!key) return 0; + + return key->hash; +} + +/* will duplicate a key depends on it's kind */ +int sxt_key_dup(const sxtkey_t *key, sxtkey_t **dest) +{ + int r = SXT_EKEY; + + if(!key) return SXT_EINVAL; + + if(sxt_key_public(key)) return sxt_key_dup_public(key, dest); + else if(sxt_key_private(key)) return sxt_key_dup_private(key, dest); + else return sxt_key_dup_private(key, dest); + + /* never riched */ + return r; +} + +/* will duplicate public key, if key was private or pair - it becomes public */ +int sxt_key_dup_public(const sxtkey_t *key, sxtkey_t **dest) +{ + sxtkey_t *nkey = NULL; + int r = SXT_SUCCESS; + + if(!key) return SXT_EINVAL; + + if(!sxt_key_private(key)) return SXT_EKEY; + + if(!(nkey = sxt_key_alloc())) return SXT_ENOMEM; + else nkey->flags = 0; + + switch(key->type) { + case PPKP_ED25519: /* actually the same still, but in case of other key types will differ */ + /* check first */ + if(!key->pubkey || !key->privkey) { + r = SXT_EKEY; + goto __failed; + } + + /* allocate new values */ + if(!(nkey->pubkey = malloc(ED25519_PK_LEN))) { + r = SXT_ENOMEM; + goto __failed; + } + if(!(nkey->privkey = malloc(ED25519_SK_LEN))) { + free(nkey->pubkey); + r = SXT_ENOMEM; + goto __failed; + } + + /* copy that */ + memcpy(nkey->pubkey, key->pubkey, ED25519_PK_LEN); + memcpy(nkey->privkey, key->privkey, ED25519_SK_LEN); + break; + default: /* don't now about it */ + sxt_key_free(nkey); + return SXT_EKEY; + } + + /* copy other values */ + nkey->flags |= SXT_PPKP_PUBLIC; + nkey->type = key->type; + nkey->hash = key->hash; + nkey->priv = key->priv; + + *dest = nkey; + + return r; + + __failed: + sxt_key_free(nkey); + return r; +} + +/* will duplicate private key, if key public error will returns */ +int sxt_key_dup_private(const sxtkey_t *key, sxtkey_t **dest) +{ + sxtkey_t *nkey = NULL; + int r = SXT_SUCCESS; + + if(!key) return SXT_EINVAL; + //if(sxt_key_public(key)) return SXT_EKEY; /* cannot duplicate private key from public */ + + if(!(nkey = sxt_key_alloc())) return SXT_ENOMEM; + else nkey->flags = 0; + + switch(key->type) { + case PPKP_ED25519: + /* check first */ + if(!key->pubkey || !key->privkey) { + r = SXT_EKEY; + goto __failed; + } + + /* allocate new values */ + if(!(nkey->pubkey = malloc(ED25519_PK_LEN))) { + r = SXT_ENOMEM; + goto __failed; + } + if(!(nkey->privkey = malloc(ED25519_SK_LEN))) { + free(nkey->pubkey); + r = SXT_ENOMEM; + goto __failed; + } + + /* copy that */ + memcpy(nkey->pubkey, key->pubkey, ED25519_PK_LEN); + memcpy(nkey->privkey, key->privkey, ED25519_SK_LEN); + break; + default: /* don't now about it */ + sxt_key_free(nkey); + return SXT_EKEY; + } + + /* copy other values */ + nkey->flags = SXT_PPKP_PRIVATE; + nkey->type = key->type; + nkey->hash = key->hash; + nkey->priv = key->priv; + + *dest = nkey; + + return r; + + __failed: + sxt_key_free(nkey); + return r; +} + +#if 0 +#define dbg_mark printf("%s:%d\n", __FUNCTION__, __LINE__) +#endif +int sxt_key_export_priv_file(const sxtkey_t *key, const char *file, const char *passkey, + int (*ask_passkey)(char *pkbuf, size_t length, int confirm, void *priv), + void *priv) +{ + FILE *out = NULL; + char *pass = NULL; + sxtsafebuffer_t *bin = NULL; + int r = 0; + + if(!key) return SXT_EINVAL; + if(!sxt_key_private(key)) return SXT_EKEY; + + if((out = fopen(file, "wb")) == NULL) return SXT_EIO; + + /* passkey challenge */ + if(passkey) pass = (char *)passkey; + else if(ask_passkey) { + if((pass = malloc(sizeof(char)*64)) == NULL) { + r = SXT_ENOMEM; + goto __failed; + } + r = ask_passkey(pass, 64, 1, priv); + if(r != SXT_SUCCESS) goto __failed; + } + + /* ok, get the base64 encoded data for the key */ + switch(key->type) { + case PPKP_ED25519: + r = sxt_key_export_priv_ed25519(key, pass, &bin); + if(!bin) goto __failed; + break; + default: + r = SXT_EKEY; + goto __failed; + } + + /* sxt key container as follows: ( "")\n */ + fprintf(out, "(%s \"%s\")\n", sxt_key_name(key->type), (char *)sxtsafebuffer_getdata(bin)); + + sxtsafebuffer_destroy(bin); + + __failed: + if(pass && pass != passkey) { + memset(pass, 0, sizeof(char)*64); /* clean to disallow passkeys found in coredumps */ + free(pass); + } + fclose(out); + + return r; +} + +static int sxt_key_publickey2blob_whash(const sxtkey_t *key, sxtsafebuffer_t **o) +{ + sxtsafebuffer_t *buf = NULL, *pk = NULL; + sxtrdb_t *b = NULL; + int r = SXT_SUCCESS; + + if(!key) return SXT_EINVAL; + + /* get a public key blob without hash */ + switch(key->type) { + case PPKP_ED25519: + if((r = sxt_public_ed25519_2sb(key, &pk)) != SXT_SUCCESS) + return r; + break; + default: return SXT_EKEY; + } + + if(!(b = sxtrdb_new())) { + r = SXT_ENOMEM; + goto __failed; + } + sxtrdb_print(b, "pq", sxtsafebuffer_length(pk), sxtsafebuffer_getdata(pk), + key->hash); + if(!(buf = sxtsafebuffer_new(sxtrdb_length(b)))) { + r = SXT_ENOMEM; + goto __failed; + } + memcpy(sxtsafebuffer_getdata(buf), sxtrdb_rdata(b), sxtrdb_length(b)); + + *o = buf; + + __failed: + if(pk) sxtsafebuffer_destroy(pk); + if(b) sxtrdb_free(b); + + return r; +} + +static int sxt_key_hash2blob(const sxtkey_t *key, sxtsafebuffer_t **o) +{ + sxtsafebuffer_t *buf = NULL; + sxtrdb_t *b = NULL; + int r = SXT_SUCCESS; + + if(!key) return SXT_EINVAL; + + if(!(b = sxtrdb_new())) return SXT_ENOMEM; + + sxtrdb_print(b, "q", key->hash); + if(!(buf = sxtsafebuffer_new(sxtrdb_length(b)))) { + r = SXT_ENOMEM; + goto __failed; + } + memcpy(sxtsafebuffer_getdata(buf), sxtrdb_rdata(b), sxtrdb_length(b)); + + *o = buf; + + __failed: + if(b) sxtrdb_free(b); + + return r; +} + +int sxt_key_export_public_file(const sxtkey_t *key, const char *file) +{ + FILE *out = NULL; + sxtsafebuffer_t *hashbuf = NULL, *pubkeybuf = NULL; + sxtsafebuffer_t *pubkey_sb = NULL, *hash_sb = NULL; + char *pckey = NULL, *pchash = NULL; + int r = SXT_SUCCESS; + + if(!key) return SXT_EINVAL; + if(!sxt_key_public(key)) return SXT_EKEY; + + if((out = fopen(file, "wb")) == NULL) return SXT_EIO; + + /* + * format described as follows: + * ( 'public "" "")\n + * all scoped values are base64 encoded + */ + + /* get a public key with hash blob */ + if((r = sxt_key_publickey2blob_whash(key, &pubkey_sb)) != SXT_SUCCESS) goto __failed; + + /* get key hash blob */ + if((r = sxt_key_hash2blob(key, &hash_sb)) != SXT_SUCCESS) goto __failed; + + /* allocate buffers for base64 encoded data */ + if(!(pubkeybuf = sxtsafebuffer_new(sxt_rawlen2b64len(sxtsafebuffer_length(pubkey_sb))))) { + r = SXT_ENOMEM; + goto __failed; + } + if(!(hashbuf = sxtsafebuffer_new(sxt_rawlen2b64len(sxtsafebuffer_length(hash_sb))))) { + r = SXT_ENOMEM; + goto __failed; + } + /* do base64 encode */ + sxt_b64encode_in(sxtsafebuffer_getdata(pubkey_sb), sxtsafebuffer_getdata(pubkeybuf), + sxtsafebuffer_length(pubkey_sb)); /* pubkey */ + sxt_b64encode_in(sxtsafebuffer_getdata(hash_sb), sxtsafebuffer_getdata(hashbuf), + sxtsafebuffer_length(hash_sb)); /* hash */ + + /* get cstring to output */ + if(!(pckey = sxtsafebuffer_getcstr(pubkeybuf))) { + r = SXT_ENOMEM; + goto __failed; + } + if(!(pchash = sxtsafebuffer_getcstr(hashbuf))) { + r = SXT_ENOMEM; + sxtsafebuffer_freecstr(pckey); + goto __failed; + } + + /* output this */ + fprintf(out, "(%s 'public \"%s\" \"%s\")\n", sxt_key_name(key->type), pckey, pchash); + + /* free all stuff */ + sxtsafebuffer_freecstr(pckey); + sxtsafebuffer_freecstr(pchash); + + __failed: + if(pubkey_sb) sxtsafebuffer_destroy(pubkey_sb); + if(hash_sb) sxtsafebuffer_destroy(hash_sb); + if(hashbuf) sxtsafebuffer_destroy(hashbuf); + if(pubkeybuf) sxtsafebuffer_destroy(pubkeybuf); + fclose(out); + + return r; +} + +static int sxt_key_export_priv_ed25519(const sxtkey_t *key, const char *pass, sxtsafebuffer_t **bin) +{ + int r = 0; + sxtsafebuffer_t *b64 = NULL, *pubkey_sb = NULL; + sxtrdb_t *keybuf = NULL, *privbuf = NULL; + sxtrdb_t *kdfopts = NULL; + uint32_t urand; + uint8_t flags = 0; + + if(!key) return SXT_EINVAL; + if(key->type != PPKP_ED25519) return SXT_EKEY; + + /* allocate a buffer for the key at all */ + if(!(keybuf = sxtrdb_new())) return SXT_ENOMEM; + else sxtrdb_setflags(keybuf, SXTRDB_BURN); + + /* ok firstly get private-key-data according to SXT key container doc */ + if((r = sxt_public_ed25519_2sb(key, &pubkey_sb)) != SXT_SUCCESS) goto __failed; + + /* now we need random number */ + sxt_get_random(&urand, sizeof(uint32_t), 1); + + if(!(privbuf = sxtrdb_new())) { + r = SXT_ENOMEM; + goto __failed; + } else sxtrdb_setflags(privbuf, SXTRDB_BURN); + + /* two random numbers */ + if(!sxtrdb_print(privbuf, "dd", urand, urand)) { + r = SXT_ENOMEM; + goto __failed; + } + + /* pub, priv, hash, zero padding */ + if(!sxtrdb_print(privbuf, "dpdpqb", (uint32_t)ED25519_PK_LEN, (size_t)ED25519_PK_LEN, + key->pubkey, (uint32_t)ED25519_SK_LEN, (size_t)ED25519_SK_LEN, + key->privkey, key->hash, (uint8_t)'\0')) { + r = SXT_ENOMEM; + goto __failed; + } + + /* if hash is non-zero - include it i.e. set flag */ + if(key->hash) flags |= SXT_PPKP_IHASH; + + if(pass) { /* we need to encrypt the key i.e. privbuf *must* be encrypted */ + /* to avoid yet another wheel invention, + * the following was taken from ssh implementation, i mean + * kdf and crypto in use to encrypt the key + */ + uint8_t pad = 1; + size_t keystub_len; + sxtsafebuffer_t *salt; + sxt_cipher_t *cipher = sxt_cipher_get("aes128-cbc"); + uint8_t keystub[128]; + + /* set flags */ + flags |= SXT_PPKP_ENCRYPT; + + if(!cipher) { + /* it might be in case of forgotten initialization function */ + r = SXT_EKEY; + goto __failed; + } + + /* get the salt */ + if(!(salt = sxtsafebuffer_new(16))) { + __enomem1: + sxt_cipher_free(cipher); + r = SXT_ENOMEM; + goto __failed; + } else sxt_get_random(sxtsafebuffer_getdata(salt), 16, 1); + + /* generate kdf description */ + if(!(kdfopts = sxtrdb_new())) { + sxtsafebuffer_destroy(salt); + goto __enomem1; + } + sxtrdb_print(kdfopts, "pd", 16, sxtsafebuffer_getdata(salt), (uint32_t)32); + + /* ok, now we need to get a padding, just to be sure to be aligned for the + cipher block size */ + while(sxtrdb_length(privbuf) % cipher->blksize != 0) { + if(sxtrdb_write_u8(privbuf, pad) != sizeof(uint8_t)) { + sxt_cipher_free(cipher); + r = SXT_ENOMEM; + goto __failed; + } + pad++; + } + + /* key stub */ + keystub_len = cipher->keysize/8 + cipher->blksize; + if(keystub_len > sizeof(keystub)) { + r = SXT_EKEY; + sxt_cipher_free(cipher); + goto __failed; + } + + /* bcrypt those stuff */ + if(bcrypt_pbkdf(pass, strlen(pass), sxtsafebuffer_getdata(salt), + sxtsafebuffer_length(salt), keystub, keystub_len, 32)) { + r = SXT_ERROR; + sxt_cipher_free(cipher); + goto __failed; + } + + /* encrypt with cipher */ + sxt_cipher_set_encrypt_key(cipher, keystub, keystub + cipher->keysize/8); + sxt_cipher_encrypt(cipher, sxtrdb_rdata(privbuf), sxtrdb_rdata(privbuf), sxtrdb_length(privbuf)); + + /* clean up all */ + memset(keystub, 0, sizeof(keystub)); + sxt_cipher_free(cipher); + sxtsafebuffer_destroy(salt); + } + + /* in case of non-crypted key we anyways should include encrypt options */ + if(!kdfopts) { + if(!(kdfopts = sxtrdb_new())) { + r = SXT_ENOMEM; + goto __failed; + } + sxtrdb_print(kdfopts, "pd", 3, "nil", (uint32_t)0); + } + + /* there are a time to print all required content to the buffer */ + /* <8bit flags> + * + * + * + * according to the documentation + */ + sxtrdb_print(keybuf, "sbsssppp", PPKP_MAGIC, flags, "ppkp-ed25519", + pass ? "aes128-cbc" : "nil", pass ? "bcrypt" : "nil", + sxtrdb_length(kdfopts), sxtrdb_rdata(kdfopts), + sxtsafebuffer_length(pubkey_sb), sxtsafebuffer_getdata(pubkey_sb), + sxtrdb_length(privbuf), sxtrdb_rdata(privbuf)); + + /* as described - encode all with base64 */ + b64 = sxtsafebuffer_new(sxt_rawlen2b64len(sxtrdb_length(keybuf))); + if(!b64) { + r = SXT_ENOMEM; + goto __failed; + } + /* encode buffer */ + sxt_b64encode_in((const char *)sxtrdb_rdata(keybuf), (char *)sxtsafebuffer_getdata(b64), + sxtrdb_length(keybuf)); + + /* the last ... */ + *bin = b64; + r = SXT_SUCCESS; + + __failed: + if(keybuf) sxtrdb_free(keybuf); /* container free */ + if(pubkey_sb) sxtsafebuffer_destroy(pubkey_sb); /* public key bin free */ + if(privbuf) sxtrdb_free(privbuf); /* private key buffer free */ + + return r; +} + +static int sxt_public_ed25519_2sb(const sxtkey_t *key, sxtsafebuffer_t **buf) +{ + sxtrdb_t *rbuf = NULL; + sxtsafebuffer_t *o = NULL; + int r = SXT_SUCCESS; + + if(!key->pubkey) return SXT_EKEY; + + r = sxt_public_ed25519_2rdb(key, &rbuf); + if(!rbuf) return r; + + if(!(o = sxtsafebuffer_new((size_t)sxtrdb_length(rbuf)))) { + r = SXT_ENOMEM; + goto __failed; + } + sxtsafebuffer_setdata(o, sxtrdb_rdata(rbuf), (size_t)sxtrdb_length(rbuf)); + *buf = o; + + __failed: + sxtrdb_free(rbuf); + + return r; +} + +static int sxt_public_ed25519_2rdb(const sxtkey_t *key, sxtrdb_t **out) +{ + sxtrdb_t *buf = NULL; + + if(!key->pubkey) return SXT_EKEY; + + if(!(buf = sxtrdb_new())) return SXT_ENOMEM; + else sxtrdb_setflags(buf, SXTRDB_BURN); + + if(!sxtrdb_print(buf, "dp", (uint32_t)ED25519_PK_LEN, (size_t)ED25519_PK_LEN, + key->pubkey)) { + sxtrdb_free(buf); + return SXT_EKEY; + } + + *out = buf; + + return SXT_SUCCESS; +} +