diff options
Diffstat (limited to 'source/blender/decrypt/intern/BLO_decrypt.c')
-rw-r--r-- | source/blender/decrypt/intern/BLO_decrypt.c | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/source/blender/decrypt/intern/BLO_decrypt.c b/source/blender/decrypt/intern/BLO_decrypt.c new file mode 100644 index 00000000000..4d2eefd9631 --- /dev/null +++ b/source/blender/decrypt/intern/BLO_decrypt.c @@ -0,0 +1,394 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * openssl decryption wrapper library + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "openssl/rsa.h" +#include "openssl/rc4.h" +#include "openssl/err.h" +#include "zlib.h" + +#include "GEN_messaging.h" + +#include "blenkey.h" +#include "BLO_getPubKey.h" // real and stub implemented at writestream ... + +#include "BLO_readStreamGlue.h" +#include "BLO_decrypt.h" +#include "BLO_en_de_cryptHeader.h" + +struct decryptStructType { + struct readStreamGlueStruct *streamGlue; + unsigned int streamDone; + unsigned char *deCryptKey; + int deCryptKeyLen; // NOTE: signed int + unsigned char headerbuffer[EN_DE_CRYPTHEADERSTRUCTSIZE]; + uint32_t datacrc; // crypted data checksum + struct BLO_en_de_cryptHeaderStruct *streamHeader; + RC4_KEY rc4_key; + void *endControl; +}; + + BLO_decryptStructHandle +BLO_decrypt_begin( + void *endControl) +{ + struct decryptStructType *control; + control = malloc(sizeof(struct decryptStructType)); + if (!control) return NULL; + + control->streamGlue = NULL; + control->streamDone = 0; + control->deCryptKey = NULL; + control->deCryptKeyLen = 0; + strcpy(control->headerbuffer, ""); + control->datacrc = 0; + + control->streamHeader = malloc(EN_DE_CRYPTHEADERSTRUCTSIZE); + if (!control->streamHeader) { + free(control); + return NULL; + } + + control->streamHeader->magic = 0; + control->streamHeader->length = 0; + strcpy(control->streamHeader->pubKey, ""); + control->streamHeader->pubKeyLen = 0; + strcpy(control->streamHeader->cryptedKey, ""); + control->streamHeader->cryptedKeyLen = 0; + control->streamHeader->datacrc = 0; + control->streamHeader->headercrc = 0; + control->endControl = endControl; + + return((BLO_decryptStructHandle) control); +} + + int +BLO_decrypt_process( + BLO_decryptStructHandle BLO_decryptHandle, + unsigned char *data, + unsigned int dataIn) +{ + int err = 0; + struct decryptStructType *BLO_decrypt = + (struct decryptStructType *) BLO_decryptHandle; + + if (!BLO_decrypt) { + err = BRS_SETFUNCTION(BRS_DECRYPT) | + BRS_SETGENERR(BRS_NULL); + return err; + } + + /* First check if we have our header filled in yet */ + if (BLO_decrypt->streamHeader->cryptedKeyLen == 0) { + unsigned int processed; + if (dataIn == 0) return err; /* really need data to do anything */ + processed = ((dataIn + BLO_decrypt->streamDone) <= + EN_DE_CRYPTHEADERSTRUCTSIZE) + ? dataIn : EN_DE_CRYPTHEADERSTRUCTSIZE; + memcpy(BLO_decrypt->headerbuffer + BLO_decrypt->streamDone, + data, processed); + BLO_decrypt->streamDone += processed; + dataIn -= processed; + data += processed; + if (BLO_decrypt->streamDone == EN_DE_CRYPTHEADERSTRUCTSIZE) { + /* we have the whole header, absorb it */ + struct BLO_en_de_cryptHeaderStruct *header; + uint32_t crc; + //static unsigned char rsa_e[] = "\x11"; + static unsigned char rsa_e[] = "\x01\x00\x01"; + RSA *rsa = NULL; + byte *publisherPubKey; + int publisherPubKeyLen; + + header = (struct BLO_en_de_cryptHeaderStruct *) + BLO_decrypt->headerbuffer; + crc = crc32(0L, (const Bytef *) header, + EN_DE_CRYPTHEADERSTRUCTSIZE - 4); + + if (header->magic == 'A') { +#ifndef NDEBUG + fprintf(GEN_errorstream, + "BLO_en_de_cryptHeaderStruct Magic confirmed\n"); +#endif + } else { +#ifndef NDEBUG + fprintf(GEN_errorstream, + "ERROR BLO_en_de_cryptHeaderStruct Magic NOT confirmed\n"); +#endif + err = BRS_SETFUNCTION(BRS_DECRYPT) | + BRS_SETGENERR(BRS_MAGIC); + if (BLO_decrypt->streamGlue) free(BLO_decrypt->streamGlue); + if (BLO_decrypt->streamHeader) free(BLO_decrypt->streamHeader); + if (BLO_decrypt->deCryptKey) free(BLO_decrypt->deCryptKey); + free(BLO_decrypt); + return err; + } + + if (crc == ntohl(header->headercrc)) { +#ifndef NDEBUG + fprintf(GEN_errorstream, + "BLO_en_de_cryptHeader CRC correct\n"); +#endif + } else { +#ifndef NDEBUG + fprintf(GEN_errorstream, + "ERROR BLO_en_de_cryptHeader CRC NOT correct\n"); +#endif + err = BRS_SETFUNCTION(BRS_DECRYPT) | + BRS_SETGENERR(BRS_CRCHEADER); + if (BLO_decrypt->streamGlue) free(BLO_decrypt->streamGlue); + if (BLO_decrypt->streamHeader) free(BLO_decrypt->streamHeader); + if (BLO_decrypt->deCryptKey) free(BLO_decrypt->deCryptKey); + free(BLO_decrypt); + return err; + } + BLO_decrypt->streamHeader->length = ntohl(header->length); + BLO_decrypt->streamHeader->pubKeyLen = ntohl(header->pubKeyLen); + memcpy(BLO_decrypt->streamHeader->pubKey, header->pubKey, + BLO_decrypt->streamHeader->pubKeyLen); + + // case Publisher: get the .BPkey public key + // case Player/Plugin: simply use the data stream public key + err = getPubKey(BLO_decrypt->streamHeader->pubKey, + BLO_decrypt->streamHeader->pubKeyLen, + &publisherPubKey, + &publisherPubKeyLen); + switch (err) { + case 0: + // everything OK + break; + case 1: + // publisher without a key + case 2: + // publishers keylen != + case 3: + // publishers key != + default: +#ifndef NDEBUG + fprintf(GEN_errorstream, + "ALERT users-pubKey != datastream-pubKey, stop reading\n"); +#endif + err = BRS_SETFUNCTION(BRS_DECRYPT) | + BRS_SETSPECERR(BRS_NOTOURPUBKEY); + if (BLO_decrypt->streamGlue) free(BLO_decrypt->streamGlue); + if (BLO_decrypt->streamHeader) free(BLO_decrypt->streamHeader); + if (BLO_decrypt->deCryptKey) free(BLO_decrypt->deCryptKey); + free(BLO_decrypt); + return err; + break; + } + + BLO_decrypt->streamHeader->cryptedKeyLen = + ntohl(header->cryptedKeyLen); + memcpy(BLO_decrypt->streamHeader->cryptedKey, + header->cryptedKey, + BLO_decrypt->streamHeader->cryptedKeyLen); +#ifndef NDEBUG + fprintf(GEN_errorstream, + "BLO_decrypt_process gets %u bytes\n", + (unsigned int) BLO_decrypt->streamHeader->length); +#endif + BLO_decrypt->streamHeader->datacrc = ntohl(header->datacrc); + + // finished absorbing and testing the header, create rsa key from it + rsa = RSA_new(); + if (rsa == NULL) { +#ifndef NDEBUG + fprintf(GEN_errorstream, + "Error in RSA_new\n"); +#endif + err = BRS_SETFUNCTION(BRS_DECRYPT) | + BRS_SETSPECERR(BRS_RSANEWERROR); + if (BLO_decrypt->streamGlue) free(BLO_decrypt->streamGlue); + if (BLO_decrypt->streamHeader) free(BLO_decrypt->streamHeader); + if (BLO_decrypt->deCryptKey) free(BLO_decrypt->deCryptKey); + free(BLO_decrypt); + return err; + } + // static exponent + rsa->e = BN_bin2bn(rsa_e, sizeof(rsa_e)-1, rsa->e); + + // public part into rsa->n + rsa->n = BN_bin2bn(publisherPubKey, + publisherPubKeyLen, + rsa->n); + + //DEBUG RSA_print_fp(stdout, rsa, 0); + + BLO_decrypt->deCryptKey = malloc(RSA_size(rsa) * + sizeof(unsigned char)); + if (! BLO_decrypt->deCryptKey) { + err = BRS_SETFUNCTION(BRS_DECRYPT) | + BRS_SETGENERR(BRS_MALLOC); + if (BLO_decrypt->streamGlue) free(BLO_decrypt->streamGlue); + if (BLO_decrypt->streamHeader) free(BLO_decrypt->streamHeader); + if (BLO_decrypt->deCryptKey) free(BLO_decrypt->deCryptKey); + free(BLO_decrypt); + RSA_free(rsa); + return err; + } + + // decrypt the cryptkey + BLO_decrypt->deCryptKeyLen = RSA_public_decrypt( + BLO_decrypt->streamHeader->cryptedKeyLen, + BLO_decrypt->streamHeader->cryptedKey, + BLO_decrypt->deCryptKey, + rsa, RSA_PKCS1_PADDING); + if (BLO_decrypt->deCryptKeyLen == -1) { +#ifndef NDEBUG + fprintf(GEN_errorstream, + "Error in RSA_public_decrypt %s\n", + ERR_error_string(ERR_get_error(), + NULL)); +#endif + err = BRS_SETFUNCTION(BRS_DECRYPT) | + BRS_SETSPECERR(BRS_DECRYPTERROR); + if (BLO_decrypt->streamGlue) free(BLO_decrypt->streamGlue); + if (BLO_decrypt->streamHeader) free(BLO_decrypt->streamHeader); + if (BLO_decrypt->deCryptKey) free(BLO_decrypt->deCryptKey); + free(BLO_decrypt); + RSA_free(rsa); + return err; + } + + // Finally set the RC4 deCryptKey + RC4_set_key(&(BLO_decrypt->rc4_key), + BLO_decrypt->deCryptKeyLen, + BLO_decrypt->deCryptKey); + + RSA_free(rsa); + } + } + + /* Is there really (still) new data available ? */ + if (dataIn > 0) { + unsigned char *deCryptBuf = malloc(dataIn); + if (! deCryptBuf) { + err = BRS_SETFUNCTION(BRS_DECRYPT) | + BRS_SETGENERR(BRS_MALLOC); + if (BLO_decrypt->streamGlue) free(BLO_decrypt->streamGlue); + if (BLO_decrypt->streamHeader) free(BLO_decrypt->streamHeader); + if (BLO_decrypt->deCryptKey) free(BLO_decrypt->deCryptKey); + free(BLO_decrypt); + return err; + } + + BLO_decrypt->streamDone += dataIn; + + // update datacrc + BLO_decrypt->datacrc = crc32( + BLO_decrypt->datacrc, (const Bytef *) data, dataIn); + + // TODO FIXME we might need to keylength-align the data ! + RC4(&(BLO_decrypt->rc4_key), dataIn, data, deCryptBuf); + + // give data to streamGlueRead, it will find out what to do next + err = readStreamGlue( + BLO_decrypt->endControl, + &(BLO_decrypt->streamGlue), + (unsigned char *) deCryptBuf, + dataIn); + + free(deCryptBuf); + } + return err; +} + +/** + * openssl decrypt final call and cleanup + * @param BLO_decrypt Pointer to decrypt control structure + * @retval streamGlueRead return value + */ + int +BLO_decrypt_end( + BLO_decryptStructHandle BLO_decryptHandle) +{ + int err = 0; + struct decryptStructType *BLO_decrypt = + (struct decryptStructType *) BLO_decryptHandle; + + if (!BLO_decrypt) { + err = BRS_SETFUNCTION(BRS_DECRYPT) | + BRS_SETGENERR(BRS_NULL); + if (BLO_decrypt->streamGlue) free(BLO_decrypt->streamGlue); + if (BLO_decrypt->streamHeader) free(BLO_decrypt->streamHeader); + if (BLO_decrypt->deCryptKey) free(BLO_decrypt->deCryptKey); + free(BLO_decrypt); + return err; + } + + if (BLO_decrypt->streamDone == BLO_decrypt->streamHeader->length + + EN_DE_CRYPTHEADERSTRUCTSIZE) { +#ifndef NDEBUG + fprintf(GEN_errorstream, "Crypted data length is correct\n"); +#endif + } else { +#ifndef NDEBUG + fprintf(GEN_errorstream, "Crypted data length is NOT correct\n"); +#endif + err = BRS_SETFUNCTION(BRS_DECRYPT) | + BRS_SETGENERR(BRS_DATALEN); + if (BLO_decrypt->streamGlue) free(BLO_decrypt->streamGlue); + if (BLO_decrypt->streamHeader) free(BLO_decrypt->streamHeader); + if (BLO_decrypt->deCryptKey) free(BLO_decrypt->deCryptKey); + free(BLO_decrypt); + return err; + } + + if (BLO_decrypt->datacrc == BLO_decrypt->streamHeader->datacrc) { +#ifndef NDEBUG + fprintf(GEN_errorstream, "Crypted data CRC is correct\n"); +#endif + } else { +#ifndef NDEBUG + fprintf(GEN_errorstream, "Crypted data CRC is NOT correct\n"); +#endif + err = BRS_SETFUNCTION(BRS_DECRYPT) | + BRS_SETGENERR(BRS_CRCDATA); + if (BLO_decrypt->streamGlue) free(BLO_decrypt->streamGlue); + if (BLO_decrypt->streamHeader) free(BLO_decrypt->streamHeader); + if (BLO_decrypt->deCryptKey) free(BLO_decrypt->deCryptKey); + free(BLO_decrypt); + return err; + } + + free(BLO_decrypt->streamGlue); + free(BLO_decrypt->streamHeader); + free(BLO_decrypt->deCryptKey); + free(BLO_decrypt); + + return err; +} + |