supercop

Basic CLI for supercop
git clone git://git.finwo.net/app/supercop
Log | Files | Refs | README | LICENSE

decode.c (2538B)


      1 #include <stdlib.h>
      2 #include <string.h>
      3 
      4 #include "common.h"
      5 #include "armor.h"
      6 #include "b64.h"
      7 #include "orlp/ed25519.h"
      8 
      9 #ifdef __cplusplus
     10 extern "C" {
     11 #endif
     12 
     13 // Decode one armor block into malloc'd raw bytes; NULL unless the block
     14 // exists, is valid base64, and decodes to exactly wantlen bytes.
     15 static unsigned char *asc_block_bytes(unsigned char *cipherdata, size_t len,
     16                                       const char *label, size_t wantlen) {
     17   const unsigned char *payload;
     18   size_t payloadlen;
     19   unsigned char *raw;
     20   size_t rawlen;
     21   if (!asc_find_block(cipherdata, len, label, &payload, &payloadlen)) return NULL;
     22   raw = asc_b64_decode(payload, payloadlen, &rawlen);
     23   if (!raw || rawlen != wantlen) {
     24     if (raw) free(raw);
     25     return NULL;
     26   }
     27   return raw;
     28 }
     29 
     30 static struct KeyPair *asc_pair_alloc(void) {
     31   struct KeyPair *kp = calloc(1, sizeof(struct KeyPair));
     32   if (!kp) return NULL;
     33   kp->public_key = calloc(1, 32);
     34   if (!kp->public_key) {
     35     free(kp);
     36     return NULL;
     37   }
     38   return kp;
     39 }
     40 
     41 struct KeyPair * fmt_asc_decode(unsigned char *cipherdata, size_t len) {
     42   unsigned char *privraw;
     43   unsigned char *pubraw;
     44   struct KeyPair *kp;
     45 
     46   // A PRIVATE block is authoritative for full keys: present-but-corrupt
     47   // fails closed instead of silently downgrading to pub-only.
     48   if (asc_find_block(cipherdata, len, ASC_LABEL_PRIVATE, NULL, NULL)) {
     49     privraw = asc_block_bytes(cipherdata, len, ASC_LABEL_PRIVATE, 64);
     50     if (!privraw) return NULL;
     51     kp = asc_pair_alloc();
     52     if (!kp) {
     53       free(privraw);
     54       return NULL;
     55     }
     56     kp->private_key = calloc(1, 64);
     57     if (!kp->private_key) {
     58       free(privraw);
     59       free(kp->public_key);
     60       free(kp);
     61       return NULL;
     62     }
     63     memcpy(kp->private_key, privraw, 64);
     64     if (privraw) free(privraw);
     65     ed25519_derive_pubkey(kp->public_key, kp->private_key);
     66     // An accompanying PUBLIC block must agree when present
     67     pubraw = asc_block_bytes(cipherdata, len, ASC_LABEL_PUBLIC, 32);
     68     if (pubraw) {
     69       int ok = memcmp(pubraw, kp->public_key, 32) == 0;
     70       free(pubraw);
     71       if (!ok) {
     72         keypair_free(kp);
     73         return NULL;
     74       }
     75     }
     76     return kp;
     77   }
     78 
     79   // Lone PUBLIC block (32 public bytes) decodes as a pub-only pair
     80   pubraw = asc_block_bytes(cipherdata, len, ASC_LABEL_PUBLIC, 32);
     81   if (!pubraw) return NULL;
     82   kp = asc_pair_alloc();
     83   if (!kp) {
     84     free(pubraw);
     85     return NULL;
     86   }
     87   memcpy(kp->public_key, pubraw, 32);
     88   if (pubraw) free(pubraw);
     89   return kp;
     90 }
     91 
     92 #ifdef __cplusplus
     93 } // extern "C"
     94 #endif