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