//////////////////////////////////////////////////////////////////////////////////////// // // Nestopia - NES/Famicom emulator written in C++ // // Copyright (C) 2003-2008 Martin Freij // // This file is part of Nestopia. // // Nestopia 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. // // Nestopia 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 Nestopia; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// // // Based on public domain code written by Steve Reid // //////////////////////////////////////////////////////////////////////////////////////// #include #include "NstAssert.hpp" #include "NstSha1.hpp" namespace Nes { namespace Core { namespace Sha1 { #define NST_ROL(v,b) (((v) << (b) & 0xFFFFFFFF) | ((v) >> (32 - (b)))) #define NST_BLK(p,i) (p[i&15U] = NST_ROL(p[(i+13)&15U] ^ p[(i+8)&15U] ^ p[(i+2)&15U] ^ p[i&15U],1)) #define NST_R0(p,v,w,x,y,z,i) z = (z + ((w & (x ^ y)) ^ y) + p[i] + 0x5A827999 + NST_ROL(v,5)) & 0xFFFFFFFF; w = NST_ROL(w,30) #define NST_R1(p,v,w,x,y,z,i) z = (z + ((w & (x ^ y)) ^ y) + NST_BLK(p,i) + 0x5A827999 + NST_ROL(v,5)) & 0xFFFFFFFF; w = NST_ROL(w,30) #define NST_R2(p,v,w,x,y,z,i) z = (z + (w ^ x ^ y) + NST_BLK(p,i) + 0x6ED9EBA1 + NST_ROL(v,5)) & 0xFFFFFFFF; w = NST_ROL(w,30) #define NST_R3(p,v,w,x,y,z,i) z = (z + (((w | x) & y) | (w & x)) + NST_BLK(p,i) + 0x8F1BBCDC + NST_ROL(v,5)) & 0xFFFFFFFF; w = NST_ROL(w,30) #define NST_R4(p,v,w,x,y,z,i) z = (z + (w ^ x ^ y) + NST_BLK(p,i) + 0xCA62C1D6 + NST_ROL(v,5)) & 0xFFFFFFFF; w = NST_ROL(w,30) static void Transform(dword* const NST_RESTRICT state,const byte* const NST_RESTRICT buffer) { dword p[16]; for (uint i=0; i < 16; ++i) p[i] = dword(buffer[i*4+0]) << 24 | dword(buffer[i*4+1]) << 16 | uint(buffer[i*4+2]) << 8 | buffer[i*4+3]; dword a = state[0]; dword b = state[1]; dword c = state[2]; dword d = state[3]; dword e = state[4]; NST_R0(p,a,b,c,d,e, 0); NST_R0(p,e,a,b,c,d, 1); NST_R0(p,d,e,a,b,c, 2); NST_R0(p,c,d,e,a,b, 3); NST_R0(p,b,c,d,e,a, 4); NST_R0(p,a,b,c,d,e, 5); NST_R0(p,e,a,b,c,d, 6); NST_R0(p,d,e,a,b,c, 7); NST_R0(p,c,d,e,a,b, 8); NST_R0(p,b,c,d,e,a, 9); NST_R0(p,a,b,c,d,e,10); NST_R0(p,e,a,b,c,d,11); NST_R0(p,d,e,a,b,c,12); NST_R0(p,c,d,e,a,b,13); NST_R0(p,b,c,d,e,a,14); NST_R0(p,a,b,c,d,e,15); NST_R1(p,e,a,b,c,d,16); NST_R1(p,d,e,a,b,c,17); NST_R1(p,c,d,e,a,b,18); NST_R1(p,b,c,d,e,a,19); NST_R2(p,a,b,c,d,e,20); NST_R2(p,e,a,b,c,d,21); NST_R2(p,d,e,a,b,c,22); NST_R2(p,c,d,e,a,b,23); NST_R2(p,b,c,d,e,a,24); NST_R2(p,a,b,c,d,e,25); NST_R2(p,e,a,b,c,d,26); NST_R2(p,d,e,a,b,c,27); NST_R2(p,c,d,e,a,b,28); NST_R2(p,b,c,d,e,a,29); NST_R2(p,a,b,c,d,e,30); NST_R2(p,e,a,b,c,d,31); NST_R2(p,d,e,a,b,c,32); NST_R2(p,c,d,e,a,b,33); NST_R2(p,b,c,d,e,a,34); NST_R2(p,a,b,c,d,e,35); NST_R2(p,e,a,b,c,d,36); NST_R2(p,d,e,a,b,c,37); NST_R2(p,c,d,e,a,b,38); NST_R2(p,b,c,d,e,a,39); NST_R3(p,a,b,c,d,e,40); NST_R3(p,e,a,b,c,d,41); NST_R3(p,d,e,a,b,c,42); NST_R3(p,c,d,e,a,b,43); NST_R3(p,b,c,d,e,a,44); NST_R3(p,a,b,c,d,e,45); NST_R3(p,e,a,b,c,d,46); NST_R3(p,d,e,a,b,c,47); NST_R3(p,c,d,e,a,b,48); NST_R3(p,b,c,d,e,a,49); NST_R3(p,a,b,c,d,e,50); NST_R3(p,e,a,b,c,d,51); NST_R3(p,d,e,a,b,c,52); NST_R3(p,c,d,e,a,b,53); NST_R3(p,b,c,d,e,a,54); NST_R3(p,a,b,c,d,e,55); NST_R3(p,e,a,b,c,d,56); NST_R3(p,d,e,a,b,c,57); NST_R3(p,c,d,e,a,b,58); NST_R3(p,b,c,d,e,a,59); NST_R4(p,a,b,c,d,e,60); NST_R4(p,e,a,b,c,d,61); NST_R4(p,d,e,a,b,c,62); NST_R4(p,c,d,e,a,b,63); NST_R4(p,b,c,d,e,a,64); NST_R4(p,a,b,c,d,e,65); NST_R4(p,e,a,b,c,d,66); NST_R4(p,d,e,a,b,c,67); NST_R4(p,c,d,e,a,b,68); NST_R4(p,b,c,d,e,a,69); NST_R4(p,a,b,c,d,e,70); NST_R4(p,e,a,b,c,d,71); NST_R4(p,d,e,a,b,c,72); NST_R4(p,c,d,e,a,b,73); NST_R4(p,b,c,d,e,a,74); NST_R4(p,a,b,c,d,e,75); NST_R4(p,e,a,b,c,d,76); NST_R4(p,d,e,a,b,c,77); NST_R4(p,c,d,e,a,b,78); NST_R4(p,b,c,d,e,a,79); state[0] = (state[0] + a) & 0xFFFFFFFF; state[1] = (state[1] + b) & 0xFFFFFFFF; state[2] = (state[2] + c) & 0xFFFFFFFF; state[3] = (state[3] + d) & 0xFFFFFFFF; state[4] = (state[4] + e) & 0xFFFFFFFF; } #undef NST_ROL #undef NST_BLK #undef NST_R0 #undef NST_R1 #undef NST_R2 #undef NST_R3 #undef NST_R4 void NST_CALL Compute(Key& key,const byte* data,dword length) { if (length) key.Compute( data, length ); } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("s", on) #endif Key::Key() { Clear(); } void Key::Clear() { count = 0; state[0] = 0x67452301; state[1] = 0xEFCDAB89; state[2] = 0x98BADCFE; state[3] = 0x10325476; state[4] = 0xC3D2E1F0; finalized = false; } #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif inline void Key::Update() const { if (!finalized) Finalize(); } bool Key::operator == (const Key& key) const { Update(); key.Update(); for (uint i=0; i < 5; ++i) { if (final[i] != key.final[i]) return false; } return true; } void Key::Compute(const byte* const data,const dword length) { NST_ASSERT( data && length ); finalized = false; dword i = 0, j = count & 63; count += length; if (length + j > 63) { i = 64 - j; std::memcpy( buffer+j, data, i ); Transform( state, buffer ); for (; i + 63 < length; i += 64) Transform( state, data+i ); j = 0; } std::memcpy( buffer+j, data+i, length-i ); } void Key::Finalize() const { NST_ASSERT( !finalized && sizeof(final) == sizeof(state) ); finalized = true; std::memcpy( final, state, sizeof(final) ); byte end[64+64]; const uint length = count & 63; std::memcpy( end, buffer, length ); end[length] = 0x80; const uint page = (length >= 56 ? 64 : 0); std::memset( end+length+1, 0x00, page + (64-1) - length ); end[page+56] = count >> (56 - 3) & 0xFF; end[page+57] = count >> (48 - 3) & 0xFF; end[page+58] = count >> (40 - 3) & 0xFF; end[page+59] = count >> (32 - 3) & 0xFF; end[page+60] = count >> (24 - 3) & 0xFF; end[page+61] = count >> (16 - 3) & 0xFF; end[page+62] = count >> (8 - 3) & 0xFF; end[page+63] = count << ( 3) & 0xFF; Transform( final, end ); if (page) Transform( final, end+64 ); } Key::Digest Key::GetDigest() const { Update(); return final; } } } }