From f6a7cd34c0a4336facfc4cc02ca2b7720876ffcd Mon Sep 17 00:00:00 2001 From: Alexander Vdolainen Date: Sun, 3 Jul 2016 02:28:25 +0300 Subject: [PATCH] sxt: keys import(); API changes; --- sxt/ppkp_ops.c | 700 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 655 insertions(+), 45 deletions(-) diff --git a/sxt/ppkp_ops.c b/sxt/ppkp_ops.c index 04847e2..d0f8cc9 100644 --- a/sxt/ppkp_ops.c +++ b/sxt/ppkp_ops.c @@ -49,11 +49,13 @@ #include /* locals */ -static int sxt_key_export_priv_ed25519(const sxtkey_t *key, const char *pass, sxtsafebuffer_t **bin); +static int sxtkey_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); +static int _sxtkey_check_fmtrawbuf(const char *buffer); +static int _sxtkey_privkey_decrypt(sxtrdb_t *privkey, sxtrdb_t *kdfopt, const char *passkey); -int sxt_key_generate(sxtkey_t *key, int type, int opt) +int sxtkey_generate(sxtkey_t *key, int type, int opt) { int r = 0; @@ -96,7 +98,7 @@ int sxt_key_generate(sxtkey_t *key, int type, int opt) return r; } -sxtkey_t *sxt_key_alloc(void) +sxtkey_t *sxtkey_alloc(void) { sxtkey_t *key = malloc(sizeof(sxtkey_t)); @@ -105,7 +107,7 @@ sxtkey_t *sxt_key_alloc(void) return key; } -void sxt_key_burn(sxtkey_t *key) +void sxtkey_burn(sxtkey_t *key) { if(!key) return; @@ -126,7 +128,7 @@ void sxt_key_burn(sxtkey_t *key) return; } -void sxt_key_free(sxtkey_t *key) +void sxtkey_free(sxtkey_t *key) { if(!key) return; @@ -144,7 +146,7 @@ void sxt_key_free(sxtkey_t *key) return; } -const char *sxt_key_name(int type) +const char *sxtkey_name(int type) { switch(type) { case PPKP_ED25519: @@ -155,7 +157,7 @@ const char *sxt_key_name(int type) return NULL; } -uint8_t sxt_key_type_fname(const char *name) +uint8_t sxtkey_type_fname(const char *name) { if(!name) return 0; @@ -163,25 +165,25 @@ uint8_t sxt_key_type_fname(const char *name) else return 0; } -int sxt_key_public(const sxtkey_t *key) +int sxtkey_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) +int sxtkey_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) +int sxtkey_assign_hash(sxtkey_t *key, uint64_t hash) { if(!key) return SXT_EINVAL; - if(!sxt_key_private(key)) return SXT_EINVAL; + if(!sxtkey_private(key)) return SXT_EINVAL; if(key->hash) return SXT_EKEY; else key->hash = hash; @@ -189,7 +191,7 @@ int sxt_key_assign_hash(sxtkey_t *key, uint64_t hash) return SXT_SUCCESS; } -uint64_t sxt_key_hash(const sxtkey_t *key) +uint64_t sxtkey_hash(const sxtkey_t *key) { if(!key) return 0; @@ -197,31 +199,31 @@ uint64_t sxt_key_hash(const sxtkey_t *key) } /* will duplicate a key depends on it's kind */ -int sxt_key_dup(const sxtkey_t *key, sxtkey_t **dest) +int sxtkey_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); + if(sxtkey_public(key)) return sxtkey_dup_public(key, dest); + else if(sxtkey_private(key)) return sxtkey_dup_private(key, dest); + else return sxtkey_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) +int sxtkey_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(!sxtkey_private(key)) return SXT_EKEY; - if(!(nkey = sxt_key_alloc())) return SXT_ENOMEM; + if(!(nkey = sxtkey_alloc())) return SXT_ENOMEM; else nkey->flags = 0; switch(key->type) { @@ -248,7 +250,7 @@ int sxt_key_dup_public(const sxtkey_t *key, sxtkey_t **dest) memcpy(nkey->privkey, key->privkey, ED25519_SK_LEN); break; default: /* don't now about it */ - sxt_key_free(nkey); + sxtkey_free(nkey); return SXT_EKEY; } @@ -263,12 +265,12 @@ int sxt_key_dup_public(const sxtkey_t *key, sxtkey_t **dest) return r; __failed: - sxt_key_free(nkey); + sxtkey_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) +int sxtkey_dup_private(const sxtkey_t *key, sxtkey_t **dest) { sxtkey_t *nkey = NULL; int r = SXT_SUCCESS; @@ -276,7 +278,7 @@ int sxt_key_dup_private(const sxtkey_t *key, sxtkey_t **dest) 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; + if(!(nkey = sxtkey_alloc())) return SXT_ENOMEM; else nkey->flags = 0; switch(key->type) { @@ -303,7 +305,7 @@ int sxt_key_dup_private(const sxtkey_t *key, sxtkey_t **dest) memcpy(nkey->privkey, key->privkey, ED25519_SK_LEN); break; default: /* don't now about it */ - sxt_key_free(nkey); + sxtkey_free(nkey); return SXT_EKEY; } @@ -318,16 +320,538 @@ int sxt_key_dup_private(const sxtkey_t *key, sxtkey_t **dest) return r; __failed: - sxt_key_free(nkey); + sxtkey_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) +int sxtkey_import_priv_file(const char *file, const char *passkey, + int (*ask_passkey)(char *pkbuf, size_t length, int confirm, void *priv), + void *priv, sxtkey_t **ik) +{ + FILE *stream = NULL; + char *rawfbuf = NULL, *tbuf, *tebuf, *tuple = NULL, *b64pk = NULL; + struct stat stbuf; + uint8_t keytype = 0; + int r = SXT_SUCCESS, tc = 0, tcc = 0, len; + + *ik = NULL; + + /* check input file */ + if(!file) return SXT_EINVAL; + if(stat(file, &stbuf) != 0) return SXT_EIO; + else if(!S_ISREG(stbuf.st_mode)) return SXT_EINVAL; + if(stbuf.st_size >= SXT_PPKP_MAXCSIZE) return SXT_EINVAL; + + if((stream = fopen(file, "r")) == NULL) return SXT_EIO; + + if(!(rawfbuf = malloc(stbuf.st_size + sizeof(char)))) goto __failed; + else rawfbuf[stbuf.st_size + sizeof(char)] = '\0'; + + if(fread(rawfbuf, stbuf.st_size + sizeof(char), 1, stream) != 1) { + r = SXT_EIO; + goto __failed; + } + + /* check general format */ + r = _sxtkey_check_fmtrawbuf(rawfbuf); + if(r != SXT_SUCCESS) goto __failed; + + /* now we need to get a keytype and decode b64blob */ + for(tbuf = rawfbuf, tc = 0, tcc = 0, tebuf = NULL; *tbuf != '\0'; tbuf++) { + switch(tcc) { + case 0: /* just entering */ + if(*tbuf == '(') tcc++; + break; + case 1: /* first e.g. key type plain text description */ + if(!tebuf) tebuf = tbuf; + else if(tebuf && *tbuf == ' ') { + if(!tebuf) goto __failed; + len = (tbuf - tebuf) + sizeof(char); + if(!(tuple = malloc(len))) { + r = SXT_ENOMEM; + goto __failed; + } else memset(tuple, 0, len); + + /* check keytype */ + memcpy(tuple, tebuf, len - sizeof(char)); + keytype = sxtkey_type_fname(tuple); + free(tuple); + + if(keytype == 0) { + r = SXT_EKEY; /* unsupported key type */ + goto __failed; + } + /* going further */ + tebuf = NULL; + tcc++; + } + break; + case 2: /* private key contents */ + if(!tebuf && *tbuf != ' ') tebuf = tbuf; + else if(tebuf && *tbuf == ' ') { + len = (tbuf - tebuf) + sizeof(char); + /* check format */ + if(*tebuf != '"') tc = SXT_EKEYFMT; + if(!tc && tebuf[len - 2] != '"') tc = SXT_EKEYFMT; + len -= 2; + if(tc || len <= 0) { r = tc; goto __failed; } + tebuf++; + + if(!(tuple = malloc(len))) { r = SXT_ENOMEM; goto __failed; } + else memset(tuple, 0, len); + + memcpy(tuple, tebuf, len - sizeof(char)); + b64pk = tuple; + tuple = tebuf = NULL; + tcc++; + } + break; + case 3: + if(*tbuf == ')') tcc++; + else if(*tbuf != ' ') { + r = SXT_EKEYFMT; + goto __failed; + } + break; + default: break; + } + } + + if(tcc < 3) { + r = SXT_EKEYFMT; goto __failed; + } + + r = sxtkey_privkey_import_fbase64blob(b64pk, keytype, ask_passkey, priv, ik); + + __failed: + if(stream) fclose(stream); + if(rawfbuf) free(rawfbuf); + if(b64pk) free(b64pk); + + return r; +} + +int sxtkey_privkey_import_rdbuf(sxtrdb_t *buf, uint8_t keytype, + int (*ask_passkey)(char *pkbuf, size_t length, + int confirm, void *priv), + void *priv, sxtkey_t **ik) +{ + uint8_t flags = 0, chk = 0; + char *passkey = NULL; + sxtrdb_t *kdfopt = NULL, *ctrl_pubkey = NULL, *privkey = NULL; + sxtrdb_t *ed25519_pubbuf = NULL, *ed25519_privbuf = NULL; + sxtkey_t *key = NULL; + char *keyname = NULL, *ciphername = NULL, *kdfname = NULL, *magic = NULL; + uint64_t hash = 0; + uint32_t r1 = 0, r2 = 0; + int r = SXT_SUCCESS, decrypt = 0; + + if(!buf) return SXT_EINVAL; + if(!sxtrdb_length(buf)) return SXT_EINVAL; + if(keytype == 0) return SXT_EKEY; + + r = sxtrdb_escan(buf, "sbsssRRR", &magic, &flags, &keyname, &ciphername, &kdfname, + &kdfopt, &ctrl_pubkey, &privkey); + if(r != SXT_SUCCESS) goto __failed; + + if(strcmp(PPKP_MAGIC, magic)) { /* magic should be right */ + __eekey: + r = SXT_EKEY; + goto __failed; + } + + if(strcmp(sxtkey_name(keytype), keyname)) goto __eekey; + + /* check for auth function */ + if(flags & SXT_PPKP_ENCRYPT) decrypt++; + if(decrypt && !ask_passkey) { + r = SXT_EAUTH; + goto __failed; + } + + switch(keytype) { + case PPKP_ED25519: + /* check for encryption details */ + if(decrypt) { + if(strcmp(ciphername, "aes128-cbc") || strcmp(kdfname, "bcrypt")) { + r = SXT_EKEY; + goto __failed; + } + /* get passkey */ + passkey = malloc(64*sizeof(char)); + if(!passkey) { + r = SXT_ENOMEM; + goto __failed; + } + r = ask_passkey(passkey, 63, 0, priv); + if(r != SXT_SUCCESS) { /* FIXME: might be return SXT_EAUTH here ? */ + goto __failed; + } + /* decrypt it */ + r = _sxtkey_privkey_decrypt(privkey, kdfopt, passkey); + if(r != SXT_SUCCESS) goto __failed; + } else { + /* nil expected */ + if(strcmp(ciphername, "nil") || strcmp(kdfname, "nil")) { + r = SXT_EKEY; + goto __failed; + } + } + /* here we have privkey decrypted */ + r = sxtrdb_escan(privkey, "ddRRqb", &r1, &r2, &ed25519_pubbuf, &ed25519_privbuf, &hash, &chk); + if(r != SXT_SUCCESS) { + hash = 0; + chk = 0; + r = SXT_EKEY; + goto __failed; + } + /* control check for random numbers */ + if(r1 != r2) goto __invalid; + /* control check of public keys */ + if(sxtrdb_cmp(ctrl_pubkey, ed25519_privbuf)) { + __invalid: + sxtrdb_free(ed25519_pubbuf); + sxtrdb_free(ed25519_privbuf); + r = SXT_EKEY; + goto __failed; + } + + /* alloc a key and copy data */ + if(!(key = sxtkey_alloc())) { + __enomem: + sxtrdb_free(ed25519_pubbuf); + sxtrdb_free(ed25519_privbuf); + r = SXT_ENOMEM; + goto __failed; + } + + /* allocate space */ + if(!(key->pubkey = malloc(ED25519_PK_LEN)) || + !(key->privkey = malloc(ED25519_SK_LEN))) { + if(key->pubkey) free(key->pubkey); + if(key->privkey) free(key->privkey); + sxtkey_free(key); + goto __enomem; + } + /* copy and set all required data */ + memcpy(key->pubkey, sxtrdb_rdata(ed25519_pubbuf), ED25519_PK_LEN); + memcpy(key->privkey, sxtrdb_rdata(ed25519_privbuf), ED25519_SK_LEN); + /* free it */ + sxtrdb_free(ed25519_pubbuf); + sxtrdb_free(ed25519_privbuf); + key->type = keytype; + key->hash = hash; + key->flags = SXT_PPKP_PRIVATE; + + /* and the rest */ + *ik = key; + r = SXT_SUCCESS; + break; + default: /* unsupported key type ... */ + r = SXT_EKEY; + goto __failed; + break; + } + + __failed: + /* free temproary stuff */ + if(magic) free(magic); + if(keyname) free(keyname); + if(ciphername) free(ciphername); + if(kdfname) free(kdfname); + if(passkey) { + memset(passkey, 0, 64); + free(passkey); + } + if(kdfopt) sxtrdb_free(kdfopt); + if(ctrl_pubkey) sxtrdb_free(ctrl_pubkey); + if(privkey) sxtrdb_free(privkey); + + return r; +} + +int sxtkey_privkey_import_fbase64blob(const char *b64pk, uint8_t keytype, + int (*ask_passkey)(char *pkbuf, size_t length, + int confirm, void *priv), + void *priv, sxtkey_t **ik) +{ + sxtrdb_t *fullkeybuf = NULL; + char *decoded = NULL; + int len, r = SXT_SUCCESS; + + if(!b64pk) return SXT_EINVAL; + else len = strlen(b64pk); + if(keytype == 0) return SXT_EKEY; + if(!len) return SXT_EINVAL; + + if(!(decoded = malloc(len + sizeof(char)))) return SXT_ENOMEM; + + /* decode */ + len = sxt_b64decode_in(b64pk, len, decoded, len); + if(!len) { + r = SXT_EKEYFMT; + goto __failed; + } + + /* allocate a buffer and insert raw data */ + if(!(fullkeybuf = sxtrdb_new())) { + r = SXT_ENOMEM; + goto __failed; + } else sxtrdb_setflags(fullkeybuf, SXTRDB_BURN); + sxtrdb_write_raw_head(fullkeybuf, decoded, len); + + r = sxtkey_privkey_import_rdbuf(fullkeybuf, keytype, ask_passkey, priv, ik); + + __failed: + if(decoded) { + memset(decoded, 0, len); + free(decoded); + } + if(fullkeybuf) sxtrdb_free(fullkeybuf); + + return r; +} + +int sxtkey_pubkey_import_fbase64blob(const char *b64b, uint8_t keytype, + uint64_t ctrl_hash, sxtkey_t **ik) +{ + sxtkey_t *key = NULL; + sxtrdb_t *keybuf = NULL; + char *blob = NULL, *ed25519pk = NULL; + uint64_t hash; + int len, r = SXT_SUCCESS; + + if(!b64b) return SXT_EINVAL; + if(!sxtkey_name(keytype)) return SXT_EKEY; + + /* ok, first decode */ + len = strlen(b64b) + sizeof(char); + if(!(blob = malloc(len))) return SXT_ENOMEM; + else memset(blob, 0, len); + len = sxt_b64decode_in(b64b, len - 1, blob, len); + + if(!(keybuf = sxtrdb_new())) { + r = SXT_ENOMEM; + goto __failed; + } + + switch(keytype) { + case PPKP_ED25519: + if(!(ed25519pk = malloc(ED25519_PK_LEN))) { + r = SXT_ENOMEM; + goto __failed; + } + /* */ + sxtrdb_write_raw(keybuf, blob, len); + sxtrdb_escan(keybuf, "pq", ED25519_PK_LEN, ed25519pk, &hash); + + if(hash != ctrl_hash) { + r = SXT_EKEY; + goto __failed; + } + + if(!(key = sxtkey_alloc())) { + r = SXT_ENOMEM; goto __failed; + } + key->type = keytype; + if(!(key->pubkey = malloc(ED25519_PK_LEN))) { + sxtkey_free(key); + r = SXT_ENOMEM; goto __failed; + } + key->hash = hash; + key->flags = SXT_PPKP_PUBLIC; + memcpy(key->pubkey, ed25519pk, ED25519_PK_LEN); + + r = SXT_SUCCESS; + *ik = key; + break; + default: r = SXT_EKEYFMT; break; + } + + __failed: + if(blob) free(blob); + if(keybuf) sxtrdb_free(keybuf); + if(ed25519pk) free(ed25519pk); + + return r; +} + +int sxtkey_import_public_file(const char *file, sxtkey_t **ik) +{ + FILE *stream = NULL; + char *rawfbuf = NULL, *tbuf, *tebuf, *tuple = NULL, *b64pk = NULL; + sxtrdb_t *chbuf = NULL; + int tc = 0, tcc = 0, len; + struct stat stbuf; + int r = SXT_ENOMEM; + uint64_t ctrl_hash; + uint8_t keytype = 0; + + *ik = NULL; + + if(!file) return SXT_EINVAL; + + if(stat(file, &stbuf) != 0) return SXT_EIO; + else if(!S_ISREG(stbuf.st_mode)) return SXT_EINVAL; + + if(stbuf.st_size >= SXT_PPKP_MAXCSIZE) return SXT_EINVAL; + + if((stream = fopen(file, "r")) == NULL) return SXT_EIO; + + if(!(rawfbuf = malloc(stbuf.st_size + sizeof(char)))) goto __failed; + else rawfbuf[stbuf.st_size + sizeof(char)] = '\0'; + + if(fread(rawfbuf, stbuf.st_size + sizeof(char), 1, stream) != 1) { + r = SXT_EIO; + goto __failed; + } + + /* check general format */ + r = _sxtkey_check_fmtrawbuf(rawfbuf); + if(r != SXT_SUCCESS) goto __failed; + + /* ok, now we can parse it, avoid to use libsexpr here, + * to make sxt inpedendent as possible */ + for(tbuf = rawfbuf, tc = 0, tcc = 0, tebuf = NULL; *tbuf != '\0'; tbuf++) { + switch(tcc) { + case 0: /* just entering */ + if(*tbuf == '(') tcc++; + break; + case 1: /* first e.g. key type plain text description */ + if(!tebuf) tebuf = tbuf; + else if(tebuf && *tbuf == ' ') { + if(!tebuf) goto __failed; + len = (tbuf - tebuf) + sizeof(char); + if(!(tuple = malloc(len))) { + r = SXT_ENOMEM; + goto __failed; + } else memset(tuple, 0, len); + + /* check keytype */ + memcpy(tuple, tebuf, len - sizeof(char)); + keytype = sxtkey_type_fname(tuple); + free(tuple); + + if(keytype == 0) { + r = SXT_EKEY; /* unsupported key type */ + goto __failed; + } + /* going further */ + tebuf = NULL; + tcc++; + } + break; + case 2: /* public sign keyword */ + if(!tebuf && *tbuf != ' ') tebuf = tbuf; + else if(tebuf && *tbuf == ' ') { + if(*tebuf != '\'') { /* invalid format */ + r = SXT_EKEYFMT; + goto __failed; + } + + /* get tuple */ + len = (tbuf - tebuf) + sizeof(char); + if(!(tuple = malloc(len))) { + r = SXT_ENOMEM; + goto __failed; + } else memset(tuple, 0, len); + memcpy(tuple, tebuf, len - sizeof(char)); + + if(strcmp(tuple, "'public")) tc = SXT_EKEYFMT; + else tc = 0; + + free(tuple); + if(tc) { + r = tc; + goto __failed; + } + tebuf = NULL; + tcc++; + } + break; + case 3: /* key contents */ + if(!tebuf && *tbuf != ' ') tebuf = tbuf; + else if(tebuf && *tbuf == ' ') { + len = (tbuf - tebuf) + sizeof(char); + /* check format */ + if(*tebuf != '"') tc = SXT_EKEYFMT; + if(!tc && tebuf[len - 2] != '"') tc = SXT_EKEYFMT; + len -= 2; + if(tc || len <= 0) { r = tc; goto __failed; } + tebuf++; + + if(!(tuple = malloc(len))) { r = SXT_ENOMEM; goto __failed; } + else memset(tuple, 0, len); + + memcpy(tuple, tebuf, len - sizeof(char)); + b64pk = tuple; + tuple = tebuf = NULL; + tcc++; + } + break; + case 4: /* base64 encoded hash to verify contents */ + if(!tebuf && *tbuf == '"') tebuf = tbuf; + else if(tebuf && *tbuf == '"') { + tebuf++; + len = (tbuf - tebuf) + sizeof(char); + if(len <= 1) tc = SXT_EKEYFMT; + + if(tc) {r = tc; goto __failed;} + if(!(tuple = malloc(len))) { r = SXT_ENOMEM; goto __failed; } + else memset(tuple, 0, len); + memcpy(tuple, tebuf, len - 1); + + /* decode hash */ + tebuf = NULL; + if(!(tebuf = malloc(len))) { + free(tuple); + r = SXT_ENOMEM; goto __failed; + } else memset(tebuf, 0, len); + len = sxt_b64decode_in(tuple, len, tebuf, len); + + free(tuple); + if(!(chbuf = sxtrdb_new())) { + free(tebuf); + r = SXT_ENOMEM; goto __failed; + } + sxtrdb_write_raw(chbuf, tebuf, len); + sxtrdb_read_u64(chbuf, &ctrl_hash); + sxtrdb_free(chbuf); + free(tebuf); + tebuf = tuple = NULL; + tcc++; + } + break; + case 5: + if(*tbuf == ')') tcc++; + else if(*tbuf != ' ') { + r = SXT_EKEYFMT; + goto __failed; + } + break; + default: break; + } + } + + /* ok check fmt last time */ + if(tcc < 6) { + r = SXT_EKEYFMT; goto __failed; + } + + /* import from base64 encoded blob */ + r = sxtkey_pubkey_import_fbase64blob(b64pk, keytype, ctrl_hash, ik); + + __failed: + if(stream) fclose(stream); + if(rawfbuf) free(rawfbuf); + if(b64pk) free(b64pk); + + return r; +} + +int sxtkey_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; @@ -335,7 +859,7 @@ int sxt_key_export_priv_file(const sxtkey_t *key, const char *file, const char * int r = 0; if(!key) return SXT_EINVAL; - if(!sxt_key_private(key)) return SXT_EKEY; + if(!sxtkey_private(key)) return SXT_EKEY; if((out = fopen(file, "wb")) == NULL) return SXT_EIO; @@ -353,7 +877,7 @@ int sxt_key_export_priv_file(const sxtkey_t *key, const char *file, const char * /* ok, get the base64 encoded data for the key */ switch(key->type) { case PPKP_ED25519: - r = sxt_key_export_priv_ed25519(key, pass, &bin); + r = sxtkey_export_priv_ed25519(key, pass, &bin); if(!bin) goto __failed; break; default: @@ -362,7 +886,7 @@ int sxt_key_export_priv_file(const sxtkey_t *key, const char *file, const char * } /* sxt key container as follows: ( "")\n */ - fprintf(out, "(%s \"%s\")\n", sxt_key_name(key->type), (char *)sxtsafebuffer_getdata(bin)); + fprintf(out, "(%s \"%s\")\n", sxtkey_name(key->type), (char *)sxtsafebuffer_getdata(bin)); sxtsafebuffer_destroy(bin); @@ -376,7 +900,7 @@ int sxt_key_export_priv_file(const sxtkey_t *key, const char *file, const char * return r; } -static int sxt_key_publickey2blob_whash(const sxtkey_t *key, sxtsafebuffer_t **o) +static int sxtkey_publickey2blob_whash(const sxtkey_t *key, sxtsafebuffer_t **o) { sxtsafebuffer_t *buf = NULL, *pk = NULL; sxtrdb_t *b = NULL; @@ -414,7 +938,7 @@ static int sxt_key_publickey2blob_whash(const sxtkey_t *key, sxtsafebuffer_t **o return r; } -static int sxt_key_hash2blob(const sxtkey_t *key, sxtsafebuffer_t **o) +static int sxtkey_hash2blob(const sxtkey_t *key, sxtsafebuffer_t **o) { sxtsafebuffer_t *buf = NULL; sxtrdb_t *b = NULL; @@ -439,7 +963,7 @@ static int sxt_key_hash2blob(const sxtkey_t *key, sxtsafebuffer_t **o) return r; } -int sxt_key_export_public_file(const sxtkey_t *key, const char *file) +int sxtkey_export_public_file(const sxtkey_t *key, const char *file) { FILE *out = NULL; sxtsafebuffer_t *hashbuf = NULL, *pubkeybuf = NULL; @@ -448,7 +972,7 @@ int sxt_key_export_public_file(const sxtkey_t *key, const char *file) int r = SXT_SUCCESS; if(!key) return SXT_EINVAL; - if(!sxt_key_public(key)) return SXT_EKEY; + if(!sxtkey_public(key)) return SXT_EKEY; if((out = fopen(file, "wb")) == NULL) return SXT_EIO; @@ -459,10 +983,10 @@ int sxt_key_export_public_file(const sxtkey_t *key, const char *file) */ /* get a public key with hash blob */ - if((r = sxt_key_publickey2blob_whash(key, &pubkey_sb)) != SXT_SUCCESS) goto __failed; + if((r = sxtkey_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; + if((r = sxtkey_hash2blob(key, &hash_sb)) != SXT_SUCCESS) goto __failed; /* allocate buffers for base64 encoded data */ if(!(pubkeybuf = sxtsafebuffer_new(sxt_rawlen2b64len(sxtsafebuffer_length(pubkey_sb))))) { @@ -491,7 +1015,7 @@ int sxt_key_export_public_file(const sxtkey_t *key, const char *file) } /* output this */ - fprintf(out, "(%s 'public \"%s\" \"%s\")\n", sxt_key_name(key->type), pckey, pchash); + fprintf(out, "(%s 'public \"%s\" \"%s\")\n", sxtkey_name(key->type), pckey, pchash); /* free all stuff */ sxtsafebuffer_freecstr(pckey); @@ -507,7 +1031,7 @@ int sxt_key_export_public_file(const sxtkey_t *key, const char *file) return r; } -static int sxt_key_export_priv_ed25519(const sxtkey_t *key, const char *pass, sxtsafebuffer_t **bin) +static int sxtkey_export_priv_ed25519(const sxtkey_t *key, const char *pass, sxtsafebuffer_t **bin) { int r = 0; sxtsafebuffer_t *b64 = NULL, *pubkey_sb = NULL; @@ -584,7 +1108,7 @@ static int sxt_key_export_priv_ed25519(const sxtkey_t *key, const char *pass, sx sxtsafebuffer_destroy(salt); goto __enomem1; } - sxtrdb_print(kdfopts, "pd", 16, sxtsafebuffer_getdata(salt), (uint32_t)32); + 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 */ @@ -629,7 +1153,7 @@ static int sxt_key_export_priv_ed25519(const sxtkey_t *key, const char *pass, sx r = SXT_ENOMEM; goto __failed; } - sxtrdb_print(kdfopts, "pd", 3, "nil", (uint32_t)0); + sxtrdb_print(kdfopts, "Pd", 3, "nil", (uint32_t)0); } /* there are a time to print all required content to the buffer */ @@ -639,7 +1163,7 @@ static int sxt_key_export_priv_ed25519(const sxtkey_t *key, const char *pass, sx * * according to the documentation */ - sxtrdb_print(keybuf, "sbsssppp", PPKP_MAGIC, flags, "ppkp-ed25519", + 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), @@ -711,3 +1235,89 @@ static int sxt_public_ed25519_2rdb(const sxtkey_t *key, sxtrdb_t **out) return SXT_SUCCESS; } +static int _sxtkey_check_fmtrawbuf(const char *buffer) +{ + char *tbuf; + int r = SXT_SUCCESS, tc = 0, tcc = 0; + + /* currently only own container supported, + * let's checkout format: + * = () and "" + */ + for(tbuf = (char *)buffer; *tbuf != '\0'; tbuf++) { + switch(*tbuf) { + case '(': tc++; break; + case ')': tc--; break; + case '"': + if(!tc) { + r = SXT_EKEYFMT; + goto __failed; + } else tcc++; + break; + default: break; /* just ignore */ + } + } + + r = SXT_EKEYFMT; + if(tc) goto __failed; + if(tcc%2) goto __failed; + + r = SXT_SUCCESS; + + __failed: + return r; +} + +static int _sxtkey_privkey_decrypt(sxtrdb_t *privkey, sxtrdb_t *kdfopt, + const char *passkey) +{ + int r = SXT_SUCCESS; + sxtrdb_t *salt = NULL; + sxt_cipher_t *cipher = sxt_cipher_get("aes128-cbc"); + uint32_t rounds, keystub_len; + uint8_t keystub[128]; + + /* default check */ + if(!privkey || !kdfopt) return SXT_EINVAL; + if(!passkey) return SXT_EAUTH; + + /* cipher */ + if(!(cipher = sxt_cipher_get("aes128-cbc"))) return SXT_EKEY; + + /* get salt and rounds */ + if((r = sxtrdb_escan(kdfopt, "Rd", &salt, &rounds)) != SXT_SUCCESS) + goto __failed; + + /* check blob length and cipher block size */ + if(sxtrdb_length(privkey) % cipher->blksize != 0) { + r = SXT_EKEY; + goto __failed; + } + + /* bcrypt */ + keystub_len = cipher->keysize/8 + cipher->blksize; + if(keystub_len > sizeof(keystub)) { + r = SXT_EKEY; + goto __failed; + } + if(bcrypt_pbkdf(passkey, strlen(passkey), sxtrdb_rdata(salt), sxtrdb_length(salt), + keystub, keystub_len, rounds) < 0) { + memset(keystub, 0, keystub_len); + r = SXT_EAUTH; + goto __failed; + } + + /* set decrypt key and decrypt */ + cipher->f->set_decrypt_key(cipher, keystub, keystub + cipher->keysize/8); + cipher->f->decrypt(cipher, sxtrdb_rdata(privkey), sxtrdb_rdata(privkey), + sxtrdb_length(privkey)); + + /* free/burn unused data */ + memset(keystub, 0, keystub_len); + + __failed: + if(cipher) sxt_cipher_free(cipher); + if(salt) sxtrdb_free(salt); + + return r; +}