Advertisement
Reisyukaku

[C] crypto_dll.c

Nov 8th, 2014
800
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.82 KB | None | 0 0
  1. /*
  2. *       Crypto.dll
  3. *         by Reisyukaku
  4. *
  5. *   Library of encryption/decryption/hashing functions for 3DS roms
  6. *   Last Edited: Nov 23, 2014
  7. */
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <stdint.h>
  13. #include "crypto_dll.h"
  14.  
  15. enum sha256_opcodes {
  16.   // inputs
  17.   SHA256_IN_BLOCK = 0,
  18.   SHA256_IN_BUFFER = 1,
  19.   SHA256_IN_FILE = 2,
  20.   SHA256_IN_FILENAME = 3,
  21.   // outputs
  22.   SHA256_OUT_WORDS = 0, // 32 bits
  23.   SHA256_OUT_BYTES = 4,
  24.   SHA256_OUT_LONGS = 8, // 64 bits
  25.   SHA256_OUT_STRING = 12,
  26.   // flags
  27.   SHA256_LENGTH_BITS = 16, // length is in bits
  28.   SHA256_REVERSE_WORDS = 32, // reverse word order
  29.   SHA256_UPPERCASE_HEX = 64, // hex digits A-F are uppercase in string outputs
  30.   SHA256_REVERSE_ENDIAN = 64, // when not returning 32-bit words
  31. };
  32.  
  33. enum sha256_errors {
  34.   SHA256_INVALID_OPCODE = 1,
  35.   SHA256_FILE_NOT_FOUND = 2,
  36.   SHA256_INVALID_ARGUMENT = 3,
  37.   SHA256_IO_ERROR = 4,
  38.   SHA256_PREMATURE_EOF = 5,
  39. };
  40.  
  41. // SHA-256 says these are "the fractional parts of the square roots of the first eight primes".
  42. // They are, rounded to zero.
  43. #define sha256_init ((uint32_t []) {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19})
  44.  
  45. // SHA-256 says these are "the first 32 bits of the fractional parts of the cube roots of the first
  46. // 64 primes". Not putting this one to test. Copy/paste is a wonderful invention.
  47. #define sha256_constants ((uint32_t []) {                                                            \
  48.   0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,    \
  49.   0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,    \
  50.   0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,    \
  51.   0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,    \
  52.   0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,    \
  53.   0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,    \
  54.   0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,    \
  55.   0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2     \
  56. })
  57.  
  58. #define sha256_choose_function(one, two, three)    (((one) & (two)) ^ ((~(one)) & (three)))
  59. #define sha256_majority_function(one, two, three)  (((one) & (two)) ^ ((one) & (three)) ^ ((two) & (three)))
  60.  
  61. #define sha256_circular_shift(number, amount) ((((uint32_t) (number)) >> (amount)) | (((uint32_t) (number)) << (32 - (amount))))
  62.  
  63. #define sha256_shift_A(number) (sha256_circular_shift(number,  2) ^ sha256_circular_shift(number, 13) ^ sha256_circular_shift(number, 22))
  64. #define sha256_shift_B(number) (sha256_circular_shift(number,  6) ^ sha256_circular_shift(number, 11) ^ sha256_circular_shift(number, 25))
  65. #define sha256_shift_C(number) (sha256_circular_shift(number,  7) ^ sha256_circular_shift(number, 18) ^ ((number) >>  3))
  66. #define sha256_shift_D(number) (sha256_circular_shift(number, 17) ^ sha256_circular_shift(number, 19) ^ ((number) >> 10))
  67.  
  68. #define sha256_make_word_from_pointer(pointer) (                      \
  69.     (((uint32_t) (0[(const unsigned char *) (pointer)])) << 24) |     \
  70.     (((uint32_t) (1[(const unsigned char *) (pointer)])) << 16) |     \
  71.     (((uint32_t) (2[(const unsigned char *) (pointer)])) <<  8) |     \
  72.      ((uint32_t) (3[(const unsigned char *) (pointer)]))              \
  73. )
  74.  
  75. //Read Rom and xorpad, xor each byte, and write result to a file.
  76. EXPORT int cryptRomFS(char* path, char* prodCode, char* romname, uint32_t romfsOff, uint32_t fsSize, int mode){
  77.     FILE* fRom, *fXor, *fOut;
  78.     char *xorName = malloc(strlen(path)+strlen(prodCode)+strlen("0.romfs.xorpad")+1);
  79.     char *romName = malloc(strlen(path)+strlen(romname)+1);
  80.     char *outName = malloc(strlen(path)+strlen(prodCode)+strlen("-romfs.bin")+1);  
  81.     sprintf(xorName, "%s%s0.romfs.xorpad", path, prodCode);
  82.     sprintf(romName, "%s%s", path, romname);
  83.     sprintf(outName, "%s%s-romfs.bin", path, prodCode);
  84.     fRom = mode % 2 == 0 ? fopen(romName, "rb") : fopen(romName, "wb");
  85.     fOut = mode % 2 == 0 ? fopen(outName, "wb") : fopen(outName, "rb");
  86.     fXor = fopen(xorName, "rb");
  87.     free(xorName);
  88.     free(romName);
  89.     free(outName); 
  90.     if (!fRom && !fXor) {
  91.         fclose(fRom);
  92.         fclose(fXor);
  93.         fprintf(stderr, "Error while opening one of the files for reading\n");
  94.         return -1;
  95.     }
  96.     fseek(fRom, romfsOff, SEEK_SET);
  97.     fseek(fXor, 0, SEEK_SET);
  98.     fseek(fOut, 0, SEEK_SET);
  99.     int mUnit = 0x200, //1 3DS media unit
  100.             readBytes = 0,
  101.             i = 0,
  102.             j = 0;
  103.     char romByte[mUnit], xorByte[mUnit], outByte[mUnit];
  104.     printf("wut\n");
  105.     while(!(feof(fXor) || ferror(fXor) || ferror(fRom)) && (i < fsSize)){
  106.         printf("mode = %d | mod = %d\n", mode, mode % 2);
  107.         switch(mode){
  108.             case 0: //decrypt RomFS
  109.                 readBytes += fread(romByte, 1, mUnit, fRom);
  110.                 readBytes += fread(xorByte, 1, mUnit, fXor);
  111.                 for(j = 0; j < mUnit; j++){
  112.                     outByte[j] = romByte[j] ^ xorByte[j];
  113.                 }
  114.                 fwrite(outByte, 1, mUnit, fOut);
  115.                 i+=mUnit;
  116.                 break;
  117.             case 1: //encrypt RomFS
  118.                 readBytes += fread(xorByte, 1, mUnit, fXor);
  119.                 readBytes += fread(outByte, 1, mUnit, fOut);
  120.                 for(j = 0; j < mUnit; j++){
  121.                     romByte[j] = outByte[j] ^ xorByte[j];
  122.                 }
  123.                 fwrite(romByte, 1, mUnit, fRom);
  124.                 i+=mUnit;
  125.                 break;
  126.             case 2: //dump dec RomFS
  127.                 readBytes += fread(romByte, 1, mUnit, fRom);
  128.                 readBytes += fread(xorByte, 1, mUnit, fXor);
  129.                 for(j = 0; j < mUnit; j++){
  130.                     outByte[j] = romByte[j];
  131.                 }
  132.                 fwrite(outByte, 1, mUnit, fOut);
  133.                 i+=mUnit;
  134.                 break;
  135.             case 3: //up dec RomFS
  136.                 readBytes += fread(xorByte, 1, mUnit, fXor);
  137.                 readBytes += fread(outByte, 1, mUnit, fOut);
  138.                 for(j = 0; j < mUnit; j++){
  139.                     romByte[j] = outByte[j];
  140.                 }
  141.                 fwrite(romByte, 1, mUnit, fRom);
  142.                 i+=mUnit;
  143.                 break;
  144.         }
  145.     }
  146.     fclose(fRom);
  147.     fclose(fXor);
  148.     fclose(fOut);  
  149.     return 0;
  150. }
  151.  
  152. EXPORT int rehashRomFS(char* path, char* prodCode){
  153.     char *romfsName = malloc(strlen(path)+strlen(prodCode)+strlen("-romfs.bin")+1);
  154.     sprintf(romfsName, "%s%s-romfs.bin", path, prodCode);
  155.     FILE* rfs;
  156.     rfs = fopen(romfsName, "rb+");
  157.     free(romfsName);
  158.     //
  159.     fclose(rfs);
  160.     return 0;
  161. }
  162.  
  163. EXPORT int sha256 (int op, void * in, void * out, long long skip, long long length) {
  164.   if (op & ~127) return SHA256_INVALID_OPCODE;
  165.   if (!out) return SHA256_INVALID_ARGUMENT;
  166.   if (!((op & SHA256_LENGTH_BITS) || ((op & 3) == SHA256_IN_BLOCK))) length *= 8;
  167.   uint32_t hash[8];
  168.   int status = 0;
  169.   switch (op & 3) {
  170.     case SHA256_IN_FILENAME: {
  171.       if (!in) return SHA256_INVALID_ARGUMENT;
  172.       FILE * file = fopen(in, "rb");
  173.       if (!file) return SHA256_FILE_NOT_FOUND;
  174.       if (skip) {
  175.         status = fseek(file, skip, SEEK_SET);
  176.         if (status) {
  177.           fclose(file);
  178.           return SHA256_IO_ERROR;
  179.         }
  180.       }
  181.       status = sha256_hash_file(file, length, hash);
  182.       fclose(file);
  183.     } break;
  184.     case SHA256_IN_FILE:
  185.       if (!in) return SHA256_INVALID_ARGUMENT;
  186.       if (skip) {
  187.         status = fseek(in, skip, SEEK_CUR);
  188.         if (status) return SHA256_IO_ERROR;
  189.       }
  190.       status = sha256_hash_file(in, length, hash);
  191.       break;
  192.     case SHA256_IN_BUFFER:
  193.       if (length && (!in)) return SHA256_INVALID_ARGUMENT;
  194.       if (length)
  195.         sha256_hash_buffer(((const char *) in) + skip, length, hash);
  196.       else
  197.         sha256_hash_buffer(NULL, 0, hash);
  198.       break;
  199.     case SHA256_IN_BLOCK: {
  200.       void * block;
  201.       void * prevhash;
  202.       if (in) {
  203.         block = ((char *) in) + skip;
  204.         prevhash = ((char *) in) + length;
  205.       } else {
  206.         block = (void *) (intptr_t) skip;
  207.         prevhash = (void *) (intptr_t) length;
  208.       }
  209.       if (length == skip) prevhash = NULL;
  210.       if (!block) return SHA256_INVALID_ARGUMENT;
  211.       memcpy(hash, prevhash ? prevhash : sha256_init, sizeof hash);
  212.       sha256_hash_block(block, hash);
  213.     }
  214.   }
  215.   if (status) return status;
  216.   sha256_format_output(op & ~3, out, hash);
  217.   return 0;
  218. }
  219.  
  220. static void sha256_format_output (int outformat, void * out, uint32_t * hash) {
  221.   unsigned char p;
  222.   if (outformat & SHA256_REVERSE_WORDS) {
  223.     uint32_t reversed[8];
  224.     for (p = 0; p < 8; p ++) reversed[p] = hash[7 - p];
  225.     memcpy(hash, reversed, sizeof reversed);
  226.   }
  227.   switch (outformat & 12) {
  228.     case SHA256_OUT_STRING:
  229.       sha256_make_result_string(hash, out, outformat & SHA256_UPPERCASE_HEX);
  230.       return;
  231.     case SHA256_OUT_WORDS:
  232.       memcpy(out, hash, 32);
  233.       return;
  234.     case SHA256_OUT_BYTES:
  235.       for (p = 0; p < 7; p ++) sha256_convert_number_to_bytes(hash[p], (char *) out + 4 * p, outformat & SHA256_REVERSE_ENDIAN);
  236.       return;
  237.     case SHA256_OUT_LONGS: {
  238.       uint64_t * result64 = out;
  239.       for (p = 0; p < 4; p ++)
  240.         if (outformat & SHA256_REVERSE_ENDIAN)
  241.           result64[p] = (uint64_t) (hash[2 * p]) | (((uint64_t) (hash[2 * p + 1])) << 32);
  242.         else
  243.           result64[p] = (uint64_t) (hash[2 * p + 1]) | (((uint64_t) (hash[2 * p])) << 32);
  244.     }
  245.   }
  246. }
  247.  
  248. static void sha256_hash_buffer (const void * buffer, unsigned long long length, uint32_t * result) {
  249.   unsigned long long remaining = length;
  250.   const char * p = buffer;
  251.   memcpy(result, sha256_init, sizeof sha256_init);
  252.   while (remaining >= 512) {
  253.     sha256_hash_block(p, result);
  254.     remaining -= 512;
  255.     p += 64;
  256.   }
  257.   unsigned char block[64];
  258.   if (remaining) memcpy(block, p, (remaining + 7) / 8);
  259.   sha256_pad_block(block, remaining);
  260.   if (remaining >= 448) {
  261.     sha256_hash_block(block, result);
  262.     memset(block, 0, 64);
  263.   }
  264.   unsigned char pos;
  265.   for (pos = 63; length; pos --) {
  266.     block[pos] = length & 0xff;
  267.     length >>= 8;
  268.   }
  269.   sha256_hash_block(block, result);
  270. }
  271.  
  272. static int sha256_hash_file (FILE * file, unsigned long long length, uint32_t * result) {
  273.   unsigned char block[64];
  274.   memcpy(result, sha256_init, sizeof sha256_init);
  275.   unsigned long long remaining = length;
  276.   int record_length = !length;
  277.   short read_size, read_result = 0;
  278.   while ((remaining || record_length) && !(feof(file) || ferror(file))) {
  279.     if (!record_length && (remaining < 505))
  280.       read_size = (remaining + 7) / 8;
  281.     else
  282.       read_size = 64;
  283.     read_result = fread(block, 1, read_size, file);
  284.     if (ferror(file)) return SHA256_IO_ERROR;
  285.     if ((read_result < read_size) && !record_length) return SHA256_PREMATURE_EOF;
  286.     if (record_length) {
  287.       read_result <<= 3;
  288.       length += read_result;
  289.     } else {
  290.       read_result = (remaining > 512) ? 512 : remaining;
  291.       remaining -= read_result;
  292.     }
  293.     if (read_result < 512) break;
  294.     sha256_hash_block(block, result);
  295.   }
  296.   if (read_result == 512) read_result = 0;
  297.   sha256_pad_block(block, read_result);
  298.   if (read_result >= 448) {
  299.     sha256_hash_block(block, result);
  300.     memset(block, 0, 64);
  301.   }
  302.   for (read_result = 63; length; read_result --) {
  303.     block[read_result] = length & 0xff;
  304.     length >>= 8;
  305.   }
  306.   sha256_hash_block(block, result);
  307.   return 0;
  308. }
  309.  
  310. static void sha256_pad_block (void * block, unsigned short start_bit) {
  311.   char * p = block;
  312.   p[start_bit / 8] |= 1 << (7 - (start_bit % 8));
  313.   p[start_bit / 8] &= -(1 << (7 - (start_bit % 8)));
  314.   start_bit += 8 - (start_bit % 8);
  315.   if (start_bit < 512) memset(p + start_bit / 8, 0, 64 - start_bit / 8);
  316. }
  317.  
  318. static void sha256_hash_block (const void * block, uint32_t * partial) {
  319.   uint32_t words[64];
  320.   uint32_t status[8];
  321.   uint32_t x, y;
  322.   unsigned char p;
  323.   // here be dragons
  324.   for (p = 0; p < 16; p ++) {
  325.     words[p] = sha256_make_word_from_pointer(block);
  326.     block = (char *) block + 4;
  327.   }
  328.   for (; p < 64; p ++) words[p] = sha256_shift_D(words[p - 2]) + words[p - 7] + sha256_shift_C(words[p - 15]) + words[p - 16];
  329.   memcpy(status, partial, sizeof status);
  330.   for (p = 0; p < 64; p ++) {
  331.     x = status[7] + sha256_shift_B(status[4]) + sha256_choose_function(status[4], status[5], status[6]) + sha256_constants[p] + words[p];
  332.     y = sha256_shift_A(*status) + sha256_majority_function(*status, status[1], status[2]);
  333.     memmove(status + 1, status, 28);
  334.     status[4] += x;
  335.     *status = x + y;
  336.   }
  337.   for (p = 0; p < 8; p ++) partial[p] += status[p];
  338. }
  339.  
  340. static void sha256_make_result_string (const uint32_t * hash_result, char * string, int capitalize) {
  341.   string[64] = 0;
  342.   signed char n, b;
  343.   uint32_t current;
  344.   const char * digits = capitalize ? "0123456789ABCDEF" : "0123456789abcdef";
  345.   for (n = 0; n < 8; n ++) {
  346.     current = hash_result[n];
  347.     for (b = 7; b >= 0; b --) {
  348.       string[n * 8 + b] = digits[current & 0xf];
  349.       current >>= 4;
  350.     }
  351.   }
  352. }
  353.  
  354. static void sha256_convert_number_to_bytes (uint32_t number, char * bytes, int little_endian) {
  355.   unsigned char p;
  356.   for (p = 0; p < 4; p ++) {
  357.     bytes[little_endian ? p : (3 - p)] = number & 0xff;
  358.     number >>= 8;
  359.   }
  360. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement