CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Tools/SaveTool/encrypt.c
Views: 1401
/*1* PSP Software Development Kit - http://www.pspdev.org2* -----------------------------------------------------------------------3* Licensed under the BSD license, see LICENSE in PSPSDK root for details.4*5* encrypt.c - Encryption routines using sceChnnlsv6*7* Copyright (c) 2005 Jim Paris <[email protected]>8* Coypright (c) 2005 psp1239*10* $Id: encrypt.c 1560 2005-12-10 01:16:32Z jim $11*/1213#include "encrypt.h"14#include "hash.h"15#include <stdio.h>16#include <stdlib.h>17#include <string.h>18#include <malloc.h>19#include <pspchnnlsv.h>20#include "kernelcall/kernelcall.h"2122static inline int align16(unsigned int v)23{24return ((v + 0xF) >> 4) << 4;25}2627int fopen_getsize(const char *filename, FILE **fd, int *size)28{29if ((*fd = fopen(filename, "r")) == NULL)30return -1;3132fseek(*fd, 0, SEEK_END);33*size = ftell(*fd);34fseek(*fd, 0, SEEK_SET);3536if (*size <= 0) {37fclose(*fd);38return -2;39}4041return 0;42}4344/* Encrypt the given plaintext file, and update the message45authentication hashes in the param.sfo. The data_filename is46usually the final component of encrypted_filename, e.g. "DATA.BIN".47See main.c for an example of usage. */48int encrypt_file(const char *plaintext_filename,49const char *encrypted_filename,50const char *data_filename,51const char *paramsfo_filename,52const char *paramsfo_filename_out,53const unsigned char *gamekey,54const int mainSdkVersion)55{56FILE *in = NULL, *out = NULL, *sfo = NULL;57unsigned char *data = NULL, *cryptkey = NULL, *hash = NULL;58unsigned char paramsfo[0x1330];59int len, aligned_len, tmp;60int retval;6162/* Open plaintext and param.sfo files and get size */6364if (fopen_getsize(plaintext_filename, &in, &len) < 0) {65retval = -1;66goto out;67}6869if (fopen_getsize(paramsfo_filename, &sfo, &tmp) < 0) {70retval = -2;71goto out;72}7374/* Verify size of param.sfo; all known saves use this size */7576if (tmp != 0x1330) {77retval = -3;78goto out;79}8081/* Allocate buffers. data has 0x10 bytes extra for the IV. */8283aligned_len = align16(len);8485if ((data =86(unsigned char *) memalign(0x10, aligned_len + 0x10)) == NULL) {87retval = -4;88goto out;89}9091if ((cryptkey = (unsigned char *) memalign(0x10, 0x10)) == NULL) {92retval = -5;93goto out;94}9596if ((hash = (unsigned char *) memalign(0x10, 0x10)) == NULL) {97retval = -6;98goto out;99}100101/* Fill buffers. */102103memset(data + len, 0, aligned_len - len);104if (fread(data, 1, len, in) != len) {105retval = -7;106goto out;107}108109if (fread(paramsfo, 1, 0x1330, sfo) != 0x1330) {110retval = -8;111goto out;112}113114if (gamekey != NULL)115memcpy(cryptkey, gamekey, 0x10);116117/* Do the encryption */118119if ((retval = encrypt_data( gamekey ? (mainSdkVersion >= 4 ? 5 : 3) : 1, // 5 for sdk >= 4, 3 otherwise120data,121&len, &aligned_len,122hash,123gamekey ? cryptkey : NULL)) < 0) {124retval -= 1000;125goto out;126}127128/* Update the param.sfo hashes */129130if ((retval = update_hashes(paramsfo, 0x1330,131data_filename, hash,132gamekey ? 3 : 1)) < 0) {133retval -= 2000;134goto out;135}136137/* Write the data to the file. encrypt_data has already set len. */138139if ((out = fopen(encrypted_filename, "w")) == NULL) {140retval = -9;141goto out;142}143144if (fwrite(data, 1, len, out) != len) {145retval = -10;146goto out;147}148149/* Reopen param.sfo, and write the updated copy out. */150151fclose(sfo);152if ((sfo = fopen(paramsfo_filename_out, "w")) == NULL) {153retval = -11;154goto out;155}156157if (fwrite(paramsfo, 1, 0x1330, sfo) != 0x1330) {158retval = -12;159goto out;160}161162/* All done. Return file length. */163164retval = len;165166out:167if(out) fclose(out);168if(hash) free(hash);169if(cryptkey) free(cryptkey);170if(data) free(data);171if(sfo) fclose(sfo);172if(in) fclose(in);173174return retval;175}176177/* Do the actual hardware encryption.178mode is 3 for saves with a cryptkey, or 1 otherwise179data, dataLen, and cryptkey must be multiples of 0x10.180cryptkey is NULL if mode == 1.181*/182int encrypt_data(unsigned int mode,183unsigned char *data,184int *dataLen,185int *alignedLen,186unsigned char *hash,187unsigned char *cryptkey)188{189pspChnnlsvContext1 ctx1;190pspChnnlsvContext2 ctx2;191192/* Make room for the IV in front of the data. */193memmove(data + 0x10, data, *alignedLen);194195/* Set up buffers */196memset(&ctx1, 0, sizeof(pspChnnlsvContext1));197memset(&ctx2, 0, sizeof(pspChnnlsvContext2));198memset(hash, 0, 0x10);199memset(data, 0, 0x10);200201/* Build the 0x10-byte IV and setup encryption */202if (sceChnnlsv_ABFDFC8B_(&ctx2, mode, 1, data, cryptkey) < 0)203return -1;204if (sceChnnlsv_E7833020_(&ctx1, mode) < 0)205return -2;206if (sceChnnlsv_F21A1FCA_(&ctx1, data, 0x10) < 0)207return -3;208if (sceChnnlsv_850A7FA1_(&ctx2, data + 0x10, *alignedLen) < 0)209return -4;210211/* Clear any extra bytes left from the previous steps */212memset(data + 0x10 + *dataLen, 0, *alignedLen - *dataLen);213214/* Encrypt the data */215if (sceChnnlsv_F21A1FCA_(&ctx1, data + 0x10, *alignedLen) < 0)216return -5;217218/* Verify encryption */219if (sceChnnlsv_21BE78B4_(&ctx2) < 0)220return -6;221222/* Build the file hash from this PSP */223if (sceChnnlsv_C4C494F8_(&ctx1, hash, cryptkey) < 0)224return -7;225226/* Adjust sizes to account for IV */227*alignedLen += 0x10;228*dataLen += 0x10;229230/* All done */231return 0;232}233234235