1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdbool.h> 18 #include <string.h> 19 #include <stdint.h> 20 #include <stdlib.h> 21 #include <stdio.h> 22 #include <inttypes.h> 23 24 #include <nanohub/aes.h> 25 #include <nanohub/sha2.h> 26 #include <nanohub/nanohub.h> 27 #include <nanohub/nanoapp.h> 28 29 static FILE* urandom = NULL; 30 31 static void cleanup(void) 32 { 33 if (urandom) 34 fclose(urandom); 35 } 36 37 static void rand_bytes(void *dst, uint32_t len) 38 { 39 if (!urandom) { 40 urandom = fopen("/dev/urandom", "rb"); 41 if (!urandom) { 42 fprintf(stderr, "Failed to open /dev/urandom. Cannot procceed!\n"); 43 exit(2); 44 } 45 46 //it might not matter, but we still like to try to cleanup after ourselves 47 (void)atexit(cleanup); 48 } 49 50 if (len != fread(dst, 1, len, urandom)) { 51 fprintf(stderr, "Failed to read /dev/urandom. Cannot procceed!\n"); 52 exit(2); 53 } 54 } 55 56 static int handleEncrypt(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint64_t keyId, uint32_t *key) 57 { 58 uint32_t i; 59 struct AesCbcContext ctx; 60 struct ImageHeader *image; 61 uint32_t *data; 62 struct Sha2state shaState; 63 bool err = false; 64 struct AppSecEncrHdr encr; 65 uint32_t padLen = 0; 66 uint8_t *buf = *pbuf; 67 68 encr.keyID = keyId; 69 70 //FIXME: compatibility: all the devices has google secret key with id 1, so we 71 // can't simply change and enforce new key naming policy; 72 // first, key upload mechanism shall start working, and then we can have 73 // all the policies we want; for now, disable enforcement 74 75 // if (encr.keyID <= 0xFFFF) 76 // encr.keyID = AES_KEY_ID(encr.keyID); 77 78 fprintf(stderr, "Using Key ID: %016" PRIX64 "\n", encr.keyID); 79 rand_bytes(encr.IV, sizeof(encr.IV)); 80 printHash(stderr, "Using IV", encr.IV, AES_BLOCK_WORDS); 81 82 if (bufUsed <= sizeof(*image)) { 83 fprintf(stderr, "Input file is too small\n"); 84 return 2; 85 } 86 87 encr.dataLen = bufUsed; 88 89 if (((bufUsed - sizeof(*image)) % AES_BLOCK_SIZE) != 0) 90 padLen = AES_BLOCK_SIZE - ((bufUsed - sizeof(*image)) % AES_BLOCK_SIZE); 91 92 if (padLen) { 93 reallocOrDie(buf, bufUsed + padLen); 94 rand_bytes(buf + bufUsed, padLen); 95 bufUsed += padLen; 96 fprintf(stderr, "Padded to %" PRIu32 " bytes\n", bufUsed); 97 *pbuf = buf; 98 } 99 100 image = (struct ImageHeader *)buf; 101 102 if (bufUsed >= sizeof(*image) && image->aosp.magic == NANOAPP_AOSP_MAGIC && 103 image->aosp.header_version == 1 && image->layout.magic == GOOGLE_LAYOUT_MAGIC) { 104 fprintf(stderr, "Found AOSP header\n"); 105 } else { 106 fprintf(stderr, "Unknown binary format\n"); 107 return 2; 108 } 109 110 if ((image->aosp.flags & NANOAPP_SIGNED_FLAG) != 0) { 111 fprintf(stderr, "data is marked as signed; encryption is not possible for signed data\n"); 112 return 2; 113 } 114 if ((image->aosp.flags & NANOAPP_ENCRYPTED_FLAG) != 0) { 115 fprintf(stderr, "data is marked as encrypted; encryption is not possible for encrypted data\n"); 116 return 2; 117 } 118 119 image->aosp.flags |= NANOAPP_ENCRYPTED_FLAG; 120 fwrite(image, sizeof(*image), 1, out); 121 data = (uint32_t *)(image + 1); 122 fprintf(stderr, "orig len: %" PRIu32 " bytes\n", encr.dataLen); 123 bufUsed -= sizeof(*image); 124 encr.dataLen -= sizeof(*image); 125 fwrite(&encr, sizeof(encr), 1, out); 126 sha2init(&shaState); 127 128 //encrypt and emit data 129 aesCbcInitForEncr(&ctx, key, encr.IV); 130 uint32_t outBuf[AES_BLOCK_WORDS]; 131 for (i = 0; i < bufUsed/sizeof(uint32_t); i += AES_BLOCK_WORDS) { 132 aesCbcEncr(&ctx, data + i, outBuf); 133 int32_t sz = encr.dataLen - (i * sizeof(uint32_t)); 134 sz = sz > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : sz; 135 if (sz > 0) { 136 sha2processBytes(&shaState, data + i, sz); 137 fwrite(outBuf, AES_BLOCK_SIZE, 1, out); 138 } 139 } 140 const uint32_t *hash = sha2finish(&shaState); 141 142 printHash(stderr, "HASH", hash, SHA2_HASH_WORDS); 143 144 // finally, encrypt and output SHA2 hash 145 aesCbcEncr(&ctx, hash, outBuf); 146 fwrite(outBuf, AES_BLOCK_SIZE, 1, out); 147 aesCbcEncr(&ctx, hash + AES_BLOCK_WORDS, outBuf); 148 err = fwrite(outBuf, AES_BLOCK_SIZE, 1, out) != 1; 149 150 return err ? 2 : 0; 151 } 152 153 static int handleDecrypt(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t *key) 154 { 155 struct AesCbcContext ctx; 156 struct ImageHeader *image; 157 struct Sha2state shaState; 158 struct AppSecEncrHdr *encr; 159 uint32_t *data; 160 bool err = false; 161 uint32_t fileHash[((SHA2_HASH_WORDS + AES_BLOCK_WORDS - 1) / AES_BLOCK_WORDS) * AES_BLOCK_WORDS], fileHashSz; 162 uint32_t outBuf[AES_BLOCK_WORDS]; 163 uint32_t i; 164 uint8_t *buf = *pbuf; 165 166 //parse header 167 image = (struct ImageHeader*)buf; 168 if (bufUsed >= (sizeof(*image) + sizeof(*encr)) && 169 image->aosp.header_version == 1 && image->aosp.magic == NANOAPP_AOSP_MAGIC && 170 image->layout.magic == GOOGLE_LAYOUT_MAGIC) { 171 fprintf(stderr, "Found AOSP header\n"); 172 if (!(image->aosp.flags & NANOAPP_ENCRYPTED_FLAG)) { 173 fprintf(stderr, "data is not marked as encrypted; can't decrypt\n"); 174 return 2; 175 } 176 image->aosp.flags &= ~NANOAPP_ENCRYPTED_FLAG; 177 data = (uint32_t *)(image + 1); 178 encr = (struct AppSecEncrHdr *)data; 179 data = (uint32_t *)(encr + 1); 180 bufUsed -= sizeof(*image) + sizeof(*encr); 181 } else { 182 fprintf(stderr, "Unknown binary format\n"); 183 return 2; 184 } 185 186 if (encr->dataLen > bufUsed) { 187 fprintf(stderr, "Claimed output size of %" PRIu32 "b invalid\n", encr->dataLen); 188 return 2; 189 } 190 fprintf(stderr, "Original size %" PRIu32 "b (%" PRIu32 "b of padding present)\n", 191 encr->dataLen, bufUsed - encr->dataLen); 192 if (!encr->keyID) { 193 fprintf(stderr, "Input data has invalid key ID\n"); 194 return 2; 195 } 196 fprintf(stderr, "Using Key ID: %016" PRIX64 "\n", encr->keyID); 197 printHash(stderr, "Using IV", encr->IV, AES_BLOCK_WORDS); 198 199 fwrite(image, sizeof(*image), 1, out); 200 //decrypt and emit data 201 aesCbcInitForDecr(&ctx, key, encr->IV); 202 fileHashSz = 0; 203 sha2init(&shaState); 204 for (i = 0; i < bufUsed / sizeof(uint32_t); i += AES_BLOCK_WORDS) { 205 int32_t size = encr->dataLen - i * sizeof(uint32_t); 206 aesCbcDecr(&ctx, data + i, outBuf); 207 if (size > AES_BLOCK_SIZE) 208 size = AES_BLOCK_SIZE; 209 if (size > 0) { 210 sha2processBytes(&shaState, outBuf, size); 211 err = fwrite(outBuf, size, 1, out) != 1; 212 } else if (fileHashSz < sizeof(fileHash)) { 213 memcpy(((uint8_t*)fileHash) + fileHashSz, outBuf, AES_BLOCK_SIZE); 214 fileHashSz += AES_BLOCK_SIZE; 215 } else { 216 fprintf(stderr, "Too much input data\n"); 217 return 2; 218 } 219 } 220 const uint32_t *calcHash = sha2finish(&shaState); 221 printHash(stderr, "HASH [calc]", calcHash, SHA2_HASH_WORDS); 222 printHash(stderr, "HASH [file]", fileHash, SHA2_HASH_WORDS); 223 224 bool verify = memcmp(fileHash, calcHash, SHA2_HASH_SIZE) == 0; 225 fprintf(stderr, "hash verification: %s\n", verify ? "passed" : "failed"); 226 if (!verify) 227 return 2; 228 229 if (!err) 230 fprintf(stderr, "Done\n"); 231 232 return err ? 2 : 0; 233 } 234 235 static void fatalUsage(const char *name, const char *msg, const char *arg) 236 { 237 if (msg && arg) 238 fprintf(stderr, "Error: %s: %s\n\n", msg, arg); 239 else if (msg) 240 fprintf(stderr, "Error: %s\n\n", msg); 241 242 fprintf(stderr, "USAGE: %s [-e] [-d] [-i <key id>] [-k <key file>] <input file> [<output file>]\n" 243 " -i : 64-bit hex number != 0\n" 244 " -e : encrypt post-processed file\n" 245 " -d : decrypt encrypted post-processed file\n" 246 " -k : binary file (32 byte size) containing AES-256 secret key\n" 247 , name); 248 exit(1); 249 } 250 251 int main(int argc, char **argv) 252 { 253 uint32_t bufUsed = 0; 254 uint8_t *buf = NULL; 255 uint64_t keyId = 0; 256 int ret = -1; 257 uint32_t *u32Arg = NULL; 258 uint64_t *u64Arg = NULL; 259 const char **strArg = NULL; 260 const char *appName = argv[0]; 261 const char *posArg[2] = { NULL }; 262 uint32_t posArgCnt = 0; 263 FILE *out = NULL; 264 const char *prev = NULL; 265 bool decrypt = false; 266 bool encrypt = false; 267 const char *keyFile = NULL; 268 int multi = 0; 269 uint32_t key[AES_KEY_WORDS]; 270 271 for (int i = 1; i < argc; i++) { 272 char *end = NULL; 273 if (argv[i][0] == '-') { 274 prev = argv[i]; 275 if (!strcmp(argv[i], "-d")) 276 decrypt = true; 277 else if (!strcmp(argv[i], "-e")) 278 encrypt = true; 279 else if (!strcmp(argv[i], "-k")) 280 strArg = &keyFile; 281 else if (!strcmp(argv[i], "-i")) 282 u64Arg = &keyId; 283 else 284 fatalUsage(appName, "unknown argument", argv[i]); 285 } else { 286 if (u64Arg) { 287 uint64_t tmp = strtoull(argv[i], &end, 16); 288 if (*end == '\0') 289 *u64Arg = tmp; 290 u64Arg = NULL; 291 } else if (u32Arg) { 292 uint32_t tmp = strtoul(argv[i], &end, 16); 293 if (*end == '\0') 294 *u32Arg = tmp; 295 u32Arg = NULL; 296 } else if (strArg) { 297 *strArg = argv[i]; 298 strArg = NULL; 299 } else { 300 if (posArgCnt < 2) 301 posArg[posArgCnt++] = argv[i]; 302 else 303 fatalUsage(appName, "too many positional arguments", argv[i]); 304 } 305 prev = 0; 306 } 307 } 308 if (prev) 309 fatalUsage(appName, "missing argument after", prev); 310 311 if (!posArgCnt) 312 fatalUsage(appName, "missing input file name", NULL); 313 314 if (encrypt) 315 multi++; 316 if (decrypt) 317 multi++; 318 319 if (multi != 1) 320 fatalUsage(appName, "select either -d or -e", NULL); 321 322 if (!keyFile) 323 fatalUsage(appName, "no key file given", NULL); 324 325 if (encrypt && !keyId) 326 fatalUsage(appName, "Non-zero Key ID must be given to encrypt data", NULL); 327 328 //read key 329 if (!readFile(key, sizeof(key), keyFile)) 330 fatalUsage(appName, "Key file does not exist or has incorrect size", keyFile); 331 332 buf = loadFile(posArg[0], &bufUsed); 333 fprintf(stderr, "Read %" PRIu32 " bytes\n", bufUsed); 334 335 if (!posArg[1]) 336 out = stdout; 337 else 338 out = fopen(posArg[1], "w"); 339 if (!out) 340 fatalUsage(appName, "failed to create/open output file", posArg[1]); 341 342 if (encrypt) 343 ret = handleEncrypt(&buf, bufUsed, out, keyId, key); 344 else if (decrypt) 345 ret = handleDecrypt(&buf, bufUsed, out, key); 346 347 free(buf); 348 fclose(out); 349 return ret; 350 } 351