| 
									
										
										
										
											2016-06-18 14:46:12 +02:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*  file_access_encrypted.cpp                                            */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							|  |  |  | /*                    http://www.godotengine.org                         */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2017-01-01 22:01:57 +01:00
										 |  |  | /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							| 
									
										
										
										
											2016-06-18 14:46:12 +02:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the       */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including   */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to */ | 
					
						
							|  |  |  | /* the following conditions:                                             */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be        */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.       */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | #include "file_access_encrypted.h"
 | 
					
						
							|  |  |  | #include "aes256.h"
 | 
					
						
							|  |  |  | #include "md5.h"
 | 
					
						
							|  |  |  | #include "os/copymem.h"
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | #include "print_string.h"
 | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | #define COMP_MAGIC 0x43454447
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 11:28:43 -03:00
										 |  |  | #include "core/variant.h"
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | Error FileAccessEncrypted::open_and_parse(FileAccess *p_base,const Vector<uint8_t>& p_key,Mode p_mode) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-30 11:28:43 -03:00
										 |  |  | 	//print_line("open and parse!");
 | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 	ERR_FAIL_COND_V(file!=NULL,ERR_ALREADY_IN_USE); | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 	ERR_FAIL_COND_V(p_key.size()!=32,ERR_INVALID_PARAMETER); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pos=0; | 
					
						
							|  |  |  | 	eofed=false; | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (p_mode==MODE_WRITE_AES256) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		data.clear(); | 
					
						
							|  |  |  | 		writing=true; | 
					
						
							|  |  |  | 		file=p_base; | 
					
						
							|  |  |  | 		mode=p_mode; | 
					
						
							|  |  |  | 		key=p_key; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 	} else if (p_mode==MODE_READ) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-24 01:35:47 -03:00
										 |  |  | 		writing=false; | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 		key=p_key; | 
					
						
							|  |  |  | 		uint32_t magic = p_base->get_32(); | 
					
						
							|  |  |  | 		print_line("MAGIC: "+itos(magic)); | 
					
						
							|  |  |  | 		ERR_FAIL_COND_V(magic!=COMP_MAGIC,ERR_FILE_UNRECOGNIZED); | 
					
						
							|  |  |  | 		mode=Mode(p_base->get_32()); | 
					
						
							|  |  |  | 		ERR_FAIL_INDEX_V(mode,MODE_MAX,ERR_FILE_CORRUPT); | 
					
						
							|  |  |  | 		ERR_FAIL_COND_V(mode==0,ERR_FILE_CORRUPT); | 
					
						
							|  |  |  | 		print_line("MODE: "+itos(mode)); | 
					
						
							|  |  |  | 		unsigned char md5d[16]; | 
					
						
							|  |  |  | 		p_base->get_buffer(md5d,16); | 
					
						
							|  |  |  | 		length=p_base->get_64(); | 
					
						
							|  |  |  | 		base=p_base->get_pos(); | 
					
						
							|  |  |  | 		ERR_FAIL_COND_V(p_base->get_len() < base+length, ERR_FILE_CORRUPT ); | 
					
						
							|  |  |  | 		int ds = length; | 
					
						
							|  |  |  | 		if (ds % 16) { | 
					
						
							|  |  |  | 			ds+=16-(ds % 16); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		data.resize(ds); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		int blen = p_base->get_buffer(data.ptr(),ds); | 
					
						
							|  |  |  | 		ERR_FAIL_COND_V(blen!=ds,ERR_FILE_CORRUPT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		aes256_context ctx; | 
					
						
							|  |  |  | 		aes256_init(&ctx,key.ptr()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for(size_t i=0;i<ds;i+=16) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			aes256_decrypt_ecb(&ctx,&data[i]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		aes256_done(&ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		data.resize(length); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		MD5_CTX md5; | 
					
						
							|  |  |  | 		MD5Init(&md5); | 
					
						
							|  |  |  | 		MD5Update(&md5,data.ptr(),data.size()); | 
					
						
							|  |  |  | 		MD5Final(&md5); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ERR_FAIL_COND_V(String::md5(md5.digest)!=String::md5(md5d),ERR_FILE_CORRUPT)		; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		file=p_base; | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error FileAccessEncrypted::open_and_parse_password(FileAccess *p_base,const String& p_key,Mode p_mode){ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	String cs = p_key.md5_text(); | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(cs.length()!=32,ERR_INVALID_PARAMETER); | 
					
						
							|  |  |  | 	Vector<uint8_t> key; | 
					
						
							|  |  |  | 	key.resize(32); | 
					
						
							|  |  |  | 	for(int i=0;i<32;i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		key[i]=cs[i]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return open_and_parse(p_base,key,p_mode); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error FileAccessEncrypted::_open(const String& p_path, int p_mode_flags) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | void FileAccessEncrypted::close() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!file) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (writing) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Vector<uint8_t> compressed; | 
					
						
							|  |  |  | 		size_t len = data.size(); | 
					
						
							|  |  |  | 		if (len % 16) { | 
					
						
							|  |  |  | 			len+=16-(len % 16); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 		MD5_CTX md5; | 
					
						
							|  |  |  | 		MD5Init(&md5); | 
					
						
							|  |  |  | 		MD5Update(&md5,data.ptr(),data.size()); | 
					
						
							|  |  |  | 		MD5Final(&md5); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 		compressed.resize(len); | 
					
						
							|  |  |  | 		zeromem( compressed.ptr(), len ); | 
					
						
							|  |  |  | 		for(int i=0;i<data.size();i++) { | 
					
						
							|  |  |  | 			compressed[i]=data[i]; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		aes256_context ctx; | 
					
						
							|  |  |  | 		aes256_init(&ctx,key.ptr()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for(size_t i=0;i<len;i+=16) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			aes256_encrypt_ecb(&ctx,&compressed[i]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		aes256_done(&ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		file->store_32(COMP_MAGIC); | 
					
						
							|  |  |  | 		file->store_32(mode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		file->store_buffer(md5.digest,16); | 
					
						
							|  |  |  | 		file->store_64(data.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		file->store_buffer(compressed.ptr(),compressed.size()); | 
					
						
							|  |  |  | 		file->close(); | 
					
						
							|  |  |  | 		memdelete(file); | 
					
						
							|  |  |  | 		file=NULL; | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 		data.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 		file->close(); | 
					
						
							|  |  |  | 		memdelete(file); | 
					
						
							|  |  |  | 		data.clear(); | 
					
						
							|  |  |  | 		file=NULL; | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool FileAccessEncrypted::is_open() const{ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return file!=NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FileAccessEncrypted::seek(size_t p_position){ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 	if (p_position > (size_t)data.size()) | 
					
						
							|  |  |  | 		p_position=data.size(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pos=p_position; | 
					
						
							|  |  |  | 	eofed=false; | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FileAccessEncrypted::seek_end(int64_t p_position){ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	seek( data.size() + p_position ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | size_t FileAccessEncrypted::get_pos() const{ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return pos; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | size_t FileAccessEncrypted::get_len() const{ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 	return data.size(); | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool FileAccessEncrypted::eof_reached() const{ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 	return eofed; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | uint8_t FileAccessEncrypted::get_8() const{ | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 	ERR_FAIL_COND_V(writing,0); | 
					
						
							|  |  |  | 	if (pos>=data.size()) { | 
					
						
							|  |  |  | 		eofed=true; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 	uint8_t b = data[pos]; | 
					
						
							|  |  |  | 	pos++; | 
					
						
							|  |  |  | 	return b; | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | int FileAccessEncrypted::get_buffer(uint8_t *p_dst, int p_length) const{ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 	ERR_FAIL_COND_V(writing,0); | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 	int to_copy=MIN(p_length,data.size()-pos); | 
					
						
							|  |  |  | 	for(int i=0;i<to_copy;i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		p_dst[i]=data[pos++]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (to_copy<p_length) { | 
					
						
							|  |  |  | 		eofed=true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return to_copy; | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error FileAccessEncrypted::get_error() const{ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-28 21:56:43 -03:00
										 |  |  | 	return eofed?ERR_FILE_EOF:OK; | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FileAccessEncrypted::store_buffer(const uint8_t *p_src,int p_length) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND(!writing); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pos<data.size()) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for(int i=0;i<p_length;i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			store_8(p_src[i]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if (pos==data.size()) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		data.resize(pos+p_length); | 
					
						
							|  |  |  | 		for(int i=0;i<p_length;i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			data[pos+i]=p_src[i]; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		pos+=p_length; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FileAccessEncrypted::store_8(uint8_t p_dest){ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND(!writing); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pos<data.size()) { | 
					
						
							|  |  |  | 		data[pos]=p_dest; | 
					
						
							|  |  |  | 		pos++; | 
					
						
							|  |  |  | 	} else if (pos==data.size()){ | 
					
						
							|  |  |  | 		data.push_back(p_dest); | 
					
						
							|  |  |  | 		pos++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool FileAccessEncrypted::file_exists(const String& p_name){ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	FileAccess *fa = FileAccess::open(p_name,FileAccess::READ); | 
					
						
							|  |  |  | 	if (!fa) | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	memdelete(fa); | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint64_t FileAccessEncrypted::_get_modified_time(const String& p_file){ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FileAccessEncrypted::FileAccessEncrypted() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	file=NULL; | 
					
						
							| 
									
										
										
										
											2014-05-24 01:35:47 -03:00
										 |  |  | 	pos=0; | 
					
						
							|  |  |  | 	eofed=false; | 
					
						
							|  |  |  | 	mode=MODE_MAX; | 
					
						
							|  |  |  | 	writing=false; | 
					
						
							| 
									
										
										
										
											2014-04-14 22:16:13 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FileAccessEncrypted::~FileAccessEncrypted() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (file) | 
					
						
							|  |  |  | 		close(); | 
					
						
							|  |  |  | } |