From d836202ddb5cd9b8ffc256bd540af3f580946eef Mon Sep 17 00:00:00 2001 From: The Wine Synchronizer Date: Fri, 16 Nov 2007 14:07:03 +0000 Subject: [PATCH] Autosyncing with Wine HEAD svn path=/trunk/; revision=30507 --- reactos/dll/win32/rsaenh/des.c | 1495 ++++++++ reactos/dll/win32/rsaenh/handle.c | 456 +++ reactos/dll/win32/rsaenh/handle.h | 79 + reactos/dll/win32/rsaenh/implglue.c | 437 +++ reactos/dll/win32/rsaenh/implglue.h | 100 + reactos/dll/win32/rsaenh/md2.c | 151 + reactos/dll/win32/rsaenh/mpi.c | 4422 ++++++++++++++++++++++ reactos/dll/win32/rsaenh/rc2.c | 203 + reactos/dll/win32/rsaenh/rc4.c | 108 + reactos/dll/win32/rsaenh/rsa.c | 248 ++ reactos/dll/win32/rsaenh/rsaenh.c | 3906 +++++++++++++++++++ reactos/dll/win32/rsaenh/rsaenh.rbuild | 25 + reactos/dll/win32/rsaenh/rsaenh.spec | 27 + reactos/dll/win32/rsaenh/rsaenh_ros.diff | 30 + reactos/dll/win32/rsaenh/tomcrypt.h | 611 +++ reactos/dll/win32/rsaenh/version.rc | 26 + 16 files changed, 12324 insertions(+) create mode 100644 reactos/dll/win32/rsaenh/des.c create mode 100644 reactos/dll/win32/rsaenh/handle.c create mode 100644 reactos/dll/win32/rsaenh/handle.h create mode 100644 reactos/dll/win32/rsaenh/implglue.c create mode 100644 reactos/dll/win32/rsaenh/implglue.h create mode 100644 reactos/dll/win32/rsaenh/md2.c create mode 100644 reactos/dll/win32/rsaenh/mpi.c create mode 100644 reactos/dll/win32/rsaenh/rc2.c create mode 100644 reactos/dll/win32/rsaenh/rc4.c create mode 100644 reactos/dll/win32/rsaenh/rsa.c create mode 100644 reactos/dll/win32/rsaenh/rsaenh.c create mode 100644 reactos/dll/win32/rsaenh/rsaenh.rbuild create mode 100644 reactos/dll/win32/rsaenh/rsaenh.spec create mode 100644 reactos/dll/win32/rsaenh/rsaenh_ros.diff create mode 100644 reactos/dll/win32/rsaenh/tomcrypt.h create mode 100644 reactos/dll/win32/rsaenh/version.rc diff --git a/reactos/dll/win32/rsaenh/des.c b/reactos/dll/win32/rsaenh/des.c new file mode 100644 index 00000000000..f94b6d8aa81 --- /dev/null +++ b/reactos/dll/win32/rsaenh/des.c @@ -0,0 +1,1495 @@ +/* + * dlls/rsaenh/des.c + * DES functions + * + * Copyright 2004 Michael Jung + * Based on public domain code by Tom St Denis (tomstdenis@iahu.ca) + * and Dobes Vandermeer. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * This file contains code from the LibTomCrypt cryptographic + * library written by Tom St Denis (tomstdenis@iahu.ca). LibTomCrypt + * is in the public domain. The code in this file is tailored to + * special requirements. Take a look at http://libtomcrypt.org for the + * original version. + */ + +#include "tomcrypt.h" + +#define EN0 0 +#define DE1 1 + +static const ulong32 bytebit[8] = +{ + 0200, 0100, 040, 020, 010, 04, 02, 01 +}; + +static const ulong32 bigbyte[24] = +{ + 0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL, + 0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL, + 0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL, + 0x800UL, 0x400UL, 0x200UL, 0x100UL, + 0x80UL, 0x40UL, 0x20UL, 0x10UL, + 0x8UL, 0x4UL, 0x2UL, 0x1L +}; + +/* Use the key schedule specific in the standard (ANSI X3.92-1981) */ + +static const unsigned char pc1[56] = { + 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 +}; + +static const unsigned char totrot[16] = { + 1, 2, 4, 6, + 8, 10, 12, 14, + 15, 17, 19, 21, + 23, 25, 27, 28 +}; + +static const unsigned char pc2[48] = { + 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, + 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 +}; + + +static const ulong32 SP1[64] = +{ + 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL, + 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL, + 0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL, + 0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL, + 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL, + 0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL, + 0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL, + 0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL, + 0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL, + 0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL, + 0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL, + 0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL, + 0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL, + 0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL, + 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL, + 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL +}; + +static const ulong32 SP2[64] = +{ + 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL, + 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL, + 0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL, + 0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, + 0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL, + 0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL, + 0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL, + 0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL, + 0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL, + 0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL, + 0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL, + 0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL, + 0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL, + 0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL, + 0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL, + 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL +}; + +static const ulong32 SP3[64] = +{ + 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL, + 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL, + 0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL, + 0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL, + 0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL, + 0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL, + 0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL, + 0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL, + 0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL, + 0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL, + 0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL, + 0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL, + 0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL, + 0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL, + 0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL, + 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL +}; + +static const ulong32 SP4[64] = +{ + 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, + 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL, + 0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL, + 0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL, + 0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL, + 0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL, + 0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL, + 0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL, + 0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL, + 0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL, + 0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL, + 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, + 0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL, + 0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL, + 0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL, + 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL +}; + +static const ulong32 SP5[64] = +{ + 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL, + 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL, + 0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL, + 0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL, + 0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL, + 0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL, + 0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL, + 0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL, + 0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL, + 0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL, + 0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL, + 0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL, + 0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL, + 0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL, + 0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL, + 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL +}; + +static const ulong32 SP6[64] = +{ + 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL, + 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL, + 0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL, + 0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, + 0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL, + 0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL, + 0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL, + 0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL, + 0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL, + 0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL, + 0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, + 0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL, + 0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL, + 0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL, + 0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL, + 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL +}; + +static const ulong32 SP7[64] = +{ + 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL, + 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL, + 0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL, + 0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL, + 0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL, + 0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL, + 0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL, + 0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL, + 0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL, + 0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL, + 0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL, + 0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL, + 0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL, + 0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL, + 0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL, + 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL +}; + +static const ulong32 SP8[64] = +{ + 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL, + 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL, + 0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL, + 0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL, + 0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL, + 0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL, + 0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL, + 0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL, + 0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL, + 0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL, + 0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL, + 0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL, + 0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL, + 0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL, + 0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL, + 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL +}; + +static const ulong64 des_ip[8][256] = { + +{ CONST64(0x00000000,0x00000000), CONST64(0x00000010,0x00000000), CONST64(0x00000000,0x00000010), CONST64(0x00000010,0x00000010), + CONST64(0x00001000,0x00000000), CONST64(0x00001010,0x00000000), CONST64(0x00001000,0x00000010), CONST64(0x00001010,0x00000010), + CONST64(0x00000000,0x00001000), CONST64(0x00000010,0x00001000), CONST64(0x00000000,0x00001010), CONST64(0x00000010,0x00001010), + CONST64(0x00001000,0x00001000), CONST64(0x00001010,0x00001000), CONST64(0x00001000,0x00001010), CONST64(0x00001010,0x00001010), + CONST64(0x00100000,0x00000000), CONST64(0x00100010,0x00000000), CONST64(0x00100000,0x00000010), CONST64(0x00100010,0x00000010), + CONST64(0x00101000,0x00000000), CONST64(0x00101010,0x00000000), CONST64(0x00101000,0x00000010), CONST64(0x00101010,0x00000010), + CONST64(0x00100000,0x00001000), CONST64(0x00100010,0x00001000), CONST64(0x00100000,0x00001010), CONST64(0x00100010,0x00001010), + CONST64(0x00101000,0x00001000), CONST64(0x00101010,0x00001000), CONST64(0x00101000,0x00001010), CONST64(0x00101010,0x00001010), + CONST64(0x00000000,0x00100000), CONST64(0x00000010,0x00100000), CONST64(0x00000000,0x00100010), CONST64(0x00000010,0x00100010), + CONST64(0x00001000,0x00100000), CONST64(0x00001010,0x00100000), CONST64(0x00001000,0x00100010), CONST64(0x00001010,0x00100010), + CONST64(0x00000000,0x00101000), CONST64(0x00000010,0x00101000), CONST64(0x00000000,0x00101010), CONST64(0x00000010,0x00101010), + CONST64(0x00001000,0x00101000), CONST64(0x00001010,0x00101000), CONST64(0x00001000,0x00101010), CONST64(0x00001010,0x00101010), + CONST64(0x00100000,0x00100000), CONST64(0x00100010,0x00100000), CONST64(0x00100000,0x00100010), CONST64(0x00100010,0x00100010), + CONST64(0x00101000,0x00100000), CONST64(0x00101010,0x00100000), CONST64(0x00101000,0x00100010), CONST64(0x00101010,0x00100010), + CONST64(0x00100000,0x00101000), CONST64(0x00100010,0x00101000), CONST64(0x00100000,0x00101010), CONST64(0x00100010,0x00101010), + CONST64(0x00101000,0x00101000), CONST64(0x00101010,0x00101000), CONST64(0x00101000,0x00101010), CONST64(0x00101010,0x00101010), + CONST64(0x10000000,0x00000000), CONST64(0x10000010,0x00000000), CONST64(0x10000000,0x00000010), CONST64(0x10000010,0x00000010), + CONST64(0x10001000,0x00000000), CONST64(0x10001010,0x00000000), CONST64(0x10001000,0x00000010), CONST64(0x10001010,0x00000010), + CONST64(0x10000000,0x00001000), CONST64(0x10000010,0x00001000), CONST64(0x10000000,0x00001010), CONST64(0x10000010,0x00001010), + CONST64(0x10001000,0x00001000), CONST64(0x10001010,0x00001000), CONST64(0x10001000,0x00001010), CONST64(0x10001010,0x00001010), + CONST64(0x10100000,0x00000000), CONST64(0x10100010,0x00000000), CONST64(0x10100000,0x00000010), CONST64(0x10100010,0x00000010), + CONST64(0x10101000,0x00000000), CONST64(0x10101010,0x00000000), CONST64(0x10101000,0x00000010), CONST64(0x10101010,0x00000010), + CONST64(0x10100000,0x00001000), CONST64(0x10100010,0x00001000), CONST64(0x10100000,0x00001010), CONST64(0x10100010,0x00001010), + CONST64(0x10101000,0x00001000), CONST64(0x10101010,0x00001000), CONST64(0x10101000,0x00001010), CONST64(0x10101010,0x00001010), + CONST64(0x10000000,0x00100000), CONST64(0x10000010,0x00100000), CONST64(0x10000000,0x00100010), CONST64(0x10000010,0x00100010), + CONST64(0x10001000,0x00100000), CONST64(0x10001010,0x00100000), CONST64(0x10001000,0x00100010), CONST64(0x10001010,0x00100010), + CONST64(0x10000000,0x00101000), CONST64(0x10000010,0x00101000), CONST64(0x10000000,0x00101010), CONST64(0x10000010,0x00101010), + CONST64(0x10001000,0x00101000), CONST64(0x10001010,0x00101000), CONST64(0x10001000,0x00101010), CONST64(0x10001010,0x00101010), + CONST64(0x10100000,0x00100000), CONST64(0x10100010,0x00100000), CONST64(0x10100000,0x00100010), CONST64(0x10100010,0x00100010), + CONST64(0x10101000,0x00100000), CONST64(0x10101010,0x00100000), CONST64(0x10101000,0x00100010), CONST64(0x10101010,0x00100010), + CONST64(0x10100000,0x00101000), CONST64(0x10100010,0x00101000), CONST64(0x10100000,0x00101010), CONST64(0x10100010,0x00101010), + CONST64(0x10101000,0x00101000), CONST64(0x10101010,0x00101000), CONST64(0x10101000,0x00101010), CONST64(0x10101010,0x00101010), + CONST64(0x00000000,0x10000000), CONST64(0x00000010,0x10000000), CONST64(0x00000000,0x10000010), CONST64(0x00000010,0x10000010), + CONST64(0x00001000,0x10000000), CONST64(0x00001010,0x10000000), CONST64(0x00001000,0x10000010), CONST64(0x00001010,0x10000010), + CONST64(0x00000000,0x10001000), CONST64(0x00000010,0x10001000), CONST64(0x00000000,0x10001010), CONST64(0x00000010,0x10001010), + CONST64(0x00001000,0x10001000), CONST64(0x00001010,0x10001000), CONST64(0x00001000,0x10001010), CONST64(0x00001010,0x10001010), + CONST64(0x00100000,0x10000000), CONST64(0x00100010,0x10000000), CONST64(0x00100000,0x10000010), CONST64(0x00100010,0x10000010), + CONST64(0x00101000,0x10000000), CONST64(0x00101010,0x10000000), CONST64(0x00101000,0x10000010), CONST64(0x00101010,0x10000010), + CONST64(0x00100000,0x10001000), CONST64(0x00100010,0x10001000), CONST64(0x00100000,0x10001010), CONST64(0x00100010,0x10001010), + CONST64(0x00101000,0x10001000), CONST64(0x00101010,0x10001000), CONST64(0x00101000,0x10001010), CONST64(0x00101010,0x10001010), + CONST64(0x00000000,0x10100000), CONST64(0x00000010,0x10100000), CONST64(0x00000000,0x10100010), CONST64(0x00000010,0x10100010), + CONST64(0x00001000,0x10100000), CONST64(0x00001010,0x10100000), CONST64(0x00001000,0x10100010), CONST64(0x00001010,0x10100010), + CONST64(0x00000000,0x10101000), CONST64(0x00000010,0x10101000), CONST64(0x00000000,0x10101010), CONST64(0x00000010,0x10101010), + CONST64(0x00001000,0x10101000), CONST64(0x00001010,0x10101000), CONST64(0x00001000,0x10101010), CONST64(0x00001010,0x10101010), + CONST64(0x00100000,0x10100000), CONST64(0x00100010,0x10100000), CONST64(0x00100000,0x10100010), CONST64(0x00100010,0x10100010), + CONST64(0x00101000,0x10100000), CONST64(0x00101010,0x10100000), CONST64(0x00101000,0x10100010), CONST64(0x00101010,0x10100010), + CONST64(0x00100000,0x10101000), CONST64(0x00100010,0x10101000), CONST64(0x00100000,0x10101010), CONST64(0x00100010,0x10101010), + CONST64(0x00101000,0x10101000), CONST64(0x00101010,0x10101000), CONST64(0x00101000,0x10101010), CONST64(0x00101010,0x10101010), + CONST64(0x10000000,0x10000000), CONST64(0x10000010,0x10000000), CONST64(0x10000000,0x10000010), CONST64(0x10000010,0x10000010), + CONST64(0x10001000,0x10000000), CONST64(0x10001010,0x10000000), CONST64(0x10001000,0x10000010), CONST64(0x10001010,0x10000010), + CONST64(0x10000000,0x10001000), CONST64(0x10000010,0x10001000), CONST64(0x10000000,0x10001010), CONST64(0x10000010,0x10001010), + CONST64(0x10001000,0x10001000), CONST64(0x10001010,0x10001000), CONST64(0x10001000,0x10001010), CONST64(0x10001010,0x10001010), + CONST64(0x10100000,0x10000000), CONST64(0x10100010,0x10000000), CONST64(0x10100000,0x10000010), CONST64(0x10100010,0x10000010), + CONST64(0x10101000,0x10000000), CONST64(0x10101010,0x10000000), CONST64(0x10101000,0x10000010), CONST64(0x10101010,0x10000010), + CONST64(0x10100000,0x10001000), CONST64(0x10100010,0x10001000), CONST64(0x10100000,0x10001010), CONST64(0x10100010,0x10001010), + CONST64(0x10101000,0x10001000), CONST64(0x10101010,0x10001000), CONST64(0x10101000,0x10001010), CONST64(0x10101010,0x10001010), + CONST64(0x10000000,0x10100000), CONST64(0x10000010,0x10100000), CONST64(0x10000000,0x10100010), CONST64(0x10000010,0x10100010), + CONST64(0x10001000,0x10100000), CONST64(0x10001010,0x10100000), CONST64(0x10001000,0x10100010), CONST64(0x10001010,0x10100010), + CONST64(0x10000000,0x10101000), CONST64(0x10000010,0x10101000), CONST64(0x10000000,0x10101010), CONST64(0x10000010,0x10101010), + CONST64(0x10001000,0x10101000), CONST64(0x10001010,0x10101000), CONST64(0x10001000,0x10101010), CONST64(0x10001010,0x10101010), + CONST64(0x10100000,0x10100000), CONST64(0x10100010,0x10100000), CONST64(0x10100000,0x10100010), CONST64(0x10100010,0x10100010), + CONST64(0x10101000,0x10100000), CONST64(0x10101010,0x10100000), CONST64(0x10101000,0x10100010), CONST64(0x10101010,0x10100010), + CONST64(0x10100000,0x10101000), CONST64(0x10100010,0x10101000), CONST64(0x10100000,0x10101010), CONST64(0x10100010,0x10101010), + CONST64(0x10101000,0x10101000), CONST64(0x10101010,0x10101000), CONST64(0x10101000,0x10101010), CONST64(0x10101010,0x10101010) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000008,0x00000000), CONST64(0x00000000,0x00000008), CONST64(0x00000008,0x00000008), + CONST64(0x00000800,0x00000000), CONST64(0x00000808,0x00000000), CONST64(0x00000800,0x00000008), CONST64(0x00000808,0x00000008), + CONST64(0x00000000,0x00000800), CONST64(0x00000008,0x00000800), CONST64(0x00000000,0x00000808), CONST64(0x00000008,0x00000808), + CONST64(0x00000800,0x00000800), CONST64(0x00000808,0x00000800), CONST64(0x00000800,0x00000808), CONST64(0x00000808,0x00000808), + CONST64(0x00080000,0x00000000), CONST64(0x00080008,0x00000000), CONST64(0x00080000,0x00000008), CONST64(0x00080008,0x00000008), + CONST64(0x00080800,0x00000000), CONST64(0x00080808,0x00000000), CONST64(0x00080800,0x00000008), CONST64(0x00080808,0x00000008), + CONST64(0x00080000,0x00000800), CONST64(0x00080008,0x00000800), CONST64(0x00080000,0x00000808), CONST64(0x00080008,0x00000808), + CONST64(0x00080800,0x00000800), CONST64(0x00080808,0x00000800), CONST64(0x00080800,0x00000808), CONST64(0x00080808,0x00000808), + CONST64(0x00000000,0x00080000), CONST64(0x00000008,0x00080000), CONST64(0x00000000,0x00080008), CONST64(0x00000008,0x00080008), + CONST64(0x00000800,0x00080000), CONST64(0x00000808,0x00080000), CONST64(0x00000800,0x00080008), CONST64(0x00000808,0x00080008), + CONST64(0x00000000,0x00080800), CONST64(0x00000008,0x00080800), CONST64(0x00000000,0x00080808), CONST64(0x00000008,0x00080808), + CONST64(0x00000800,0x00080800), CONST64(0x00000808,0x00080800), CONST64(0x00000800,0x00080808), CONST64(0x00000808,0x00080808), + CONST64(0x00080000,0x00080000), CONST64(0x00080008,0x00080000), CONST64(0x00080000,0x00080008), CONST64(0x00080008,0x00080008), + CONST64(0x00080800,0x00080000), CONST64(0x00080808,0x00080000), CONST64(0x00080800,0x00080008), CONST64(0x00080808,0x00080008), + CONST64(0x00080000,0x00080800), CONST64(0x00080008,0x00080800), CONST64(0x00080000,0x00080808), CONST64(0x00080008,0x00080808), + CONST64(0x00080800,0x00080800), CONST64(0x00080808,0x00080800), CONST64(0x00080800,0x00080808), CONST64(0x00080808,0x00080808), + CONST64(0x08000000,0x00000000), CONST64(0x08000008,0x00000000), CONST64(0x08000000,0x00000008), CONST64(0x08000008,0x00000008), + CONST64(0x08000800,0x00000000), CONST64(0x08000808,0x00000000), CONST64(0x08000800,0x00000008), CONST64(0x08000808,0x00000008), + CONST64(0x08000000,0x00000800), CONST64(0x08000008,0x00000800), CONST64(0x08000000,0x00000808), CONST64(0x08000008,0x00000808), + CONST64(0x08000800,0x00000800), CONST64(0x08000808,0x00000800), CONST64(0x08000800,0x00000808), CONST64(0x08000808,0x00000808), + CONST64(0x08080000,0x00000000), CONST64(0x08080008,0x00000000), CONST64(0x08080000,0x00000008), CONST64(0x08080008,0x00000008), + CONST64(0x08080800,0x00000000), CONST64(0x08080808,0x00000000), CONST64(0x08080800,0x00000008), CONST64(0x08080808,0x00000008), + CONST64(0x08080000,0x00000800), CONST64(0x08080008,0x00000800), CONST64(0x08080000,0x00000808), CONST64(0x08080008,0x00000808), + CONST64(0x08080800,0x00000800), CONST64(0x08080808,0x00000800), CONST64(0x08080800,0x00000808), CONST64(0x08080808,0x00000808), + CONST64(0x08000000,0x00080000), CONST64(0x08000008,0x00080000), CONST64(0x08000000,0x00080008), CONST64(0x08000008,0x00080008), + CONST64(0x08000800,0x00080000), CONST64(0x08000808,0x00080000), CONST64(0x08000800,0x00080008), CONST64(0x08000808,0x00080008), + CONST64(0x08000000,0x00080800), CONST64(0x08000008,0x00080800), CONST64(0x08000000,0x00080808), CONST64(0x08000008,0x00080808), + CONST64(0x08000800,0x00080800), CONST64(0x08000808,0x00080800), CONST64(0x08000800,0x00080808), CONST64(0x08000808,0x00080808), + CONST64(0x08080000,0x00080000), CONST64(0x08080008,0x00080000), CONST64(0x08080000,0x00080008), CONST64(0x08080008,0x00080008), + CONST64(0x08080800,0x00080000), CONST64(0x08080808,0x00080000), CONST64(0x08080800,0x00080008), CONST64(0x08080808,0x00080008), + CONST64(0x08080000,0x00080800), CONST64(0x08080008,0x00080800), CONST64(0x08080000,0x00080808), CONST64(0x08080008,0x00080808), + CONST64(0x08080800,0x00080800), CONST64(0x08080808,0x00080800), CONST64(0x08080800,0x00080808), CONST64(0x08080808,0x00080808), + CONST64(0x00000000,0x08000000), CONST64(0x00000008,0x08000000), CONST64(0x00000000,0x08000008), CONST64(0x00000008,0x08000008), + CONST64(0x00000800,0x08000000), CONST64(0x00000808,0x08000000), CONST64(0x00000800,0x08000008), CONST64(0x00000808,0x08000008), + CONST64(0x00000000,0x08000800), CONST64(0x00000008,0x08000800), CONST64(0x00000000,0x08000808), CONST64(0x00000008,0x08000808), + CONST64(0x00000800,0x08000800), CONST64(0x00000808,0x08000800), CONST64(0x00000800,0x08000808), CONST64(0x00000808,0x08000808), + CONST64(0x00080000,0x08000000), CONST64(0x00080008,0x08000000), CONST64(0x00080000,0x08000008), CONST64(0x00080008,0x08000008), + CONST64(0x00080800,0x08000000), CONST64(0x00080808,0x08000000), CONST64(0x00080800,0x08000008), CONST64(0x00080808,0x08000008), + CONST64(0x00080000,0x08000800), CONST64(0x00080008,0x08000800), CONST64(0x00080000,0x08000808), CONST64(0x00080008,0x08000808), + CONST64(0x00080800,0x08000800), CONST64(0x00080808,0x08000800), CONST64(0x00080800,0x08000808), CONST64(0x00080808,0x08000808), + CONST64(0x00000000,0x08080000), CONST64(0x00000008,0x08080000), CONST64(0x00000000,0x08080008), CONST64(0x00000008,0x08080008), + CONST64(0x00000800,0x08080000), CONST64(0x00000808,0x08080000), CONST64(0x00000800,0x08080008), CONST64(0x00000808,0x08080008), + CONST64(0x00000000,0x08080800), CONST64(0x00000008,0x08080800), CONST64(0x00000000,0x08080808), CONST64(0x00000008,0x08080808), + CONST64(0x00000800,0x08080800), CONST64(0x00000808,0x08080800), CONST64(0x00000800,0x08080808), CONST64(0x00000808,0x08080808), + CONST64(0x00080000,0x08080000), CONST64(0x00080008,0x08080000), CONST64(0x00080000,0x08080008), CONST64(0x00080008,0x08080008), + CONST64(0x00080800,0x08080000), CONST64(0x00080808,0x08080000), CONST64(0x00080800,0x08080008), CONST64(0x00080808,0x08080008), + CONST64(0x00080000,0x08080800), CONST64(0x00080008,0x08080800), CONST64(0x00080000,0x08080808), CONST64(0x00080008,0x08080808), + CONST64(0x00080800,0x08080800), CONST64(0x00080808,0x08080800), CONST64(0x00080800,0x08080808), CONST64(0x00080808,0x08080808), + CONST64(0x08000000,0x08000000), CONST64(0x08000008,0x08000000), CONST64(0x08000000,0x08000008), CONST64(0x08000008,0x08000008), + CONST64(0x08000800,0x08000000), CONST64(0x08000808,0x08000000), CONST64(0x08000800,0x08000008), CONST64(0x08000808,0x08000008), + CONST64(0x08000000,0x08000800), CONST64(0x08000008,0x08000800), CONST64(0x08000000,0x08000808), CONST64(0x08000008,0x08000808), + CONST64(0x08000800,0x08000800), CONST64(0x08000808,0x08000800), CONST64(0x08000800,0x08000808), CONST64(0x08000808,0x08000808), + CONST64(0x08080000,0x08000000), CONST64(0x08080008,0x08000000), CONST64(0x08080000,0x08000008), CONST64(0x08080008,0x08000008), + CONST64(0x08080800,0x08000000), CONST64(0x08080808,0x08000000), CONST64(0x08080800,0x08000008), CONST64(0x08080808,0x08000008), + CONST64(0x08080000,0x08000800), CONST64(0x08080008,0x08000800), CONST64(0x08080000,0x08000808), CONST64(0x08080008,0x08000808), + CONST64(0x08080800,0x08000800), CONST64(0x08080808,0x08000800), CONST64(0x08080800,0x08000808), CONST64(0x08080808,0x08000808), + CONST64(0x08000000,0x08080000), CONST64(0x08000008,0x08080000), CONST64(0x08000000,0x08080008), CONST64(0x08000008,0x08080008), + CONST64(0x08000800,0x08080000), CONST64(0x08000808,0x08080000), CONST64(0x08000800,0x08080008), CONST64(0x08000808,0x08080008), + CONST64(0x08000000,0x08080800), CONST64(0x08000008,0x08080800), CONST64(0x08000000,0x08080808), CONST64(0x08000008,0x08080808), + CONST64(0x08000800,0x08080800), CONST64(0x08000808,0x08080800), CONST64(0x08000800,0x08080808), CONST64(0x08000808,0x08080808), + CONST64(0x08080000,0x08080000), CONST64(0x08080008,0x08080000), CONST64(0x08080000,0x08080008), CONST64(0x08080008,0x08080008), + CONST64(0x08080800,0x08080000), CONST64(0x08080808,0x08080000), CONST64(0x08080800,0x08080008), CONST64(0x08080808,0x08080008), + CONST64(0x08080000,0x08080800), CONST64(0x08080008,0x08080800), CONST64(0x08080000,0x08080808), CONST64(0x08080008,0x08080808), + CONST64(0x08080800,0x08080800), CONST64(0x08080808,0x08080800), CONST64(0x08080800,0x08080808), CONST64(0x08080808,0x08080808) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000004,0x00000000), CONST64(0x00000000,0x00000004), CONST64(0x00000004,0x00000004), + CONST64(0x00000400,0x00000000), CONST64(0x00000404,0x00000000), CONST64(0x00000400,0x00000004), CONST64(0x00000404,0x00000004), + CONST64(0x00000000,0x00000400), CONST64(0x00000004,0x00000400), CONST64(0x00000000,0x00000404), CONST64(0x00000004,0x00000404), + CONST64(0x00000400,0x00000400), CONST64(0x00000404,0x00000400), CONST64(0x00000400,0x00000404), CONST64(0x00000404,0x00000404), + CONST64(0x00040000,0x00000000), CONST64(0x00040004,0x00000000), CONST64(0x00040000,0x00000004), CONST64(0x00040004,0x00000004), + CONST64(0x00040400,0x00000000), CONST64(0x00040404,0x00000000), CONST64(0x00040400,0x00000004), CONST64(0x00040404,0x00000004), + CONST64(0x00040000,0x00000400), CONST64(0x00040004,0x00000400), CONST64(0x00040000,0x00000404), CONST64(0x00040004,0x00000404), + CONST64(0x00040400,0x00000400), CONST64(0x00040404,0x00000400), CONST64(0x00040400,0x00000404), CONST64(0x00040404,0x00000404), + CONST64(0x00000000,0x00040000), CONST64(0x00000004,0x00040000), CONST64(0x00000000,0x00040004), CONST64(0x00000004,0x00040004), + CONST64(0x00000400,0x00040000), CONST64(0x00000404,0x00040000), CONST64(0x00000400,0x00040004), CONST64(0x00000404,0x00040004), + CONST64(0x00000000,0x00040400), CONST64(0x00000004,0x00040400), CONST64(0x00000000,0x00040404), CONST64(0x00000004,0x00040404), + CONST64(0x00000400,0x00040400), CONST64(0x00000404,0x00040400), CONST64(0x00000400,0x00040404), CONST64(0x00000404,0x00040404), + CONST64(0x00040000,0x00040000), CONST64(0x00040004,0x00040000), CONST64(0x00040000,0x00040004), CONST64(0x00040004,0x00040004), + CONST64(0x00040400,0x00040000), CONST64(0x00040404,0x00040000), CONST64(0x00040400,0x00040004), CONST64(0x00040404,0x00040004), + CONST64(0x00040000,0x00040400), CONST64(0x00040004,0x00040400), CONST64(0x00040000,0x00040404), CONST64(0x00040004,0x00040404), + CONST64(0x00040400,0x00040400), CONST64(0x00040404,0x00040400), CONST64(0x00040400,0x00040404), CONST64(0x00040404,0x00040404), + CONST64(0x04000000,0x00000000), CONST64(0x04000004,0x00000000), CONST64(0x04000000,0x00000004), CONST64(0x04000004,0x00000004), + CONST64(0x04000400,0x00000000), CONST64(0x04000404,0x00000000), CONST64(0x04000400,0x00000004), CONST64(0x04000404,0x00000004), + CONST64(0x04000000,0x00000400), CONST64(0x04000004,0x00000400), CONST64(0x04000000,0x00000404), CONST64(0x04000004,0x00000404), + CONST64(0x04000400,0x00000400), CONST64(0x04000404,0x00000400), CONST64(0x04000400,0x00000404), CONST64(0x04000404,0x00000404), + CONST64(0x04040000,0x00000000), CONST64(0x04040004,0x00000000), CONST64(0x04040000,0x00000004), CONST64(0x04040004,0x00000004), + CONST64(0x04040400,0x00000000), CONST64(0x04040404,0x00000000), CONST64(0x04040400,0x00000004), CONST64(0x04040404,0x00000004), + CONST64(0x04040000,0x00000400), CONST64(0x04040004,0x00000400), CONST64(0x04040000,0x00000404), CONST64(0x04040004,0x00000404), + CONST64(0x04040400,0x00000400), CONST64(0x04040404,0x00000400), CONST64(0x04040400,0x00000404), CONST64(0x04040404,0x00000404), + CONST64(0x04000000,0x00040000), CONST64(0x04000004,0x00040000), CONST64(0x04000000,0x00040004), CONST64(0x04000004,0x00040004), + CONST64(0x04000400,0x00040000), CONST64(0x04000404,0x00040000), CONST64(0x04000400,0x00040004), CONST64(0x04000404,0x00040004), + CONST64(0x04000000,0x00040400), CONST64(0x04000004,0x00040400), CONST64(0x04000000,0x00040404), CONST64(0x04000004,0x00040404), + CONST64(0x04000400,0x00040400), CONST64(0x04000404,0x00040400), CONST64(0x04000400,0x00040404), CONST64(0x04000404,0x00040404), + CONST64(0x04040000,0x00040000), CONST64(0x04040004,0x00040000), CONST64(0x04040000,0x00040004), CONST64(0x04040004,0x00040004), + CONST64(0x04040400,0x00040000), CONST64(0x04040404,0x00040000), CONST64(0x04040400,0x00040004), CONST64(0x04040404,0x00040004), + CONST64(0x04040000,0x00040400), CONST64(0x04040004,0x00040400), CONST64(0x04040000,0x00040404), CONST64(0x04040004,0x00040404), + CONST64(0x04040400,0x00040400), CONST64(0x04040404,0x00040400), CONST64(0x04040400,0x00040404), CONST64(0x04040404,0x00040404), + CONST64(0x00000000,0x04000000), CONST64(0x00000004,0x04000000), CONST64(0x00000000,0x04000004), CONST64(0x00000004,0x04000004), + CONST64(0x00000400,0x04000000), CONST64(0x00000404,0x04000000), CONST64(0x00000400,0x04000004), CONST64(0x00000404,0x04000004), + CONST64(0x00000000,0x04000400), CONST64(0x00000004,0x04000400), CONST64(0x00000000,0x04000404), CONST64(0x00000004,0x04000404), + CONST64(0x00000400,0x04000400), CONST64(0x00000404,0x04000400), CONST64(0x00000400,0x04000404), CONST64(0x00000404,0x04000404), + CONST64(0x00040000,0x04000000), CONST64(0x00040004,0x04000000), CONST64(0x00040000,0x04000004), CONST64(0x00040004,0x04000004), + CONST64(0x00040400,0x04000000), CONST64(0x00040404,0x04000000), CONST64(0x00040400,0x04000004), CONST64(0x00040404,0x04000004), + CONST64(0x00040000,0x04000400), CONST64(0x00040004,0x04000400), CONST64(0x00040000,0x04000404), CONST64(0x00040004,0x04000404), + CONST64(0x00040400,0x04000400), CONST64(0x00040404,0x04000400), CONST64(0x00040400,0x04000404), CONST64(0x00040404,0x04000404), + CONST64(0x00000000,0x04040000), CONST64(0x00000004,0x04040000), CONST64(0x00000000,0x04040004), CONST64(0x00000004,0x04040004), + CONST64(0x00000400,0x04040000), CONST64(0x00000404,0x04040000), CONST64(0x00000400,0x04040004), CONST64(0x00000404,0x04040004), + CONST64(0x00000000,0x04040400), CONST64(0x00000004,0x04040400), CONST64(0x00000000,0x04040404), CONST64(0x00000004,0x04040404), + CONST64(0x00000400,0x04040400), CONST64(0x00000404,0x04040400), CONST64(0x00000400,0x04040404), CONST64(0x00000404,0x04040404), + CONST64(0x00040000,0x04040000), CONST64(0x00040004,0x04040000), CONST64(0x00040000,0x04040004), CONST64(0x00040004,0x04040004), + CONST64(0x00040400,0x04040000), CONST64(0x00040404,0x04040000), CONST64(0x00040400,0x04040004), CONST64(0x00040404,0x04040004), + CONST64(0x00040000,0x04040400), CONST64(0x00040004,0x04040400), CONST64(0x00040000,0x04040404), CONST64(0x00040004,0x04040404), + CONST64(0x00040400,0x04040400), CONST64(0x00040404,0x04040400), CONST64(0x00040400,0x04040404), CONST64(0x00040404,0x04040404), + CONST64(0x04000000,0x04000000), CONST64(0x04000004,0x04000000), CONST64(0x04000000,0x04000004), CONST64(0x04000004,0x04000004), + CONST64(0x04000400,0x04000000), CONST64(0x04000404,0x04000000), CONST64(0x04000400,0x04000004), CONST64(0x04000404,0x04000004), + CONST64(0x04000000,0x04000400), CONST64(0x04000004,0x04000400), CONST64(0x04000000,0x04000404), CONST64(0x04000004,0x04000404), + CONST64(0x04000400,0x04000400), CONST64(0x04000404,0x04000400), CONST64(0x04000400,0x04000404), CONST64(0x04000404,0x04000404), + CONST64(0x04040000,0x04000000), CONST64(0x04040004,0x04000000), CONST64(0x04040000,0x04000004), CONST64(0x04040004,0x04000004), + CONST64(0x04040400,0x04000000), CONST64(0x04040404,0x04000000), CONST64(0x04040400,0x04000004), CONST64(0x04040404,0x04000004), + CONST64(0x04040000,0x04000400), CONST64(0x04040004,0x04000400), CONST64(0x04040000,0x04000404), CONST64(0x04040004,0x04000404), + CONST64(0x04040400,0x04000400), CONST64(0x04040404,0x04000400), CONST64(0x04040400,0x04000404), CONST64(0x04040404,0x04000404), + CONST64(0x04000000,0x04040000), CONST64(0x04000004,0x04040000), CONST64(0x04000000,0x04040004), CONST64(0x04000004,0x04040004), + CONST64(0x04000400,0x04040000), CONST64(0x04000404,0x04040000), CONST64(0x04000400,0x04040004), CONST64(0x04000404,0x04040004), + CONST64(0x04000000,0x04040400), CONST64(0x04000004,0x04040400), CONST64(0x04000000,0x04040404), CONST64(0x04000004,0x04040404), + CONST64(0x04000400,0x04040400), CONST64(0x04000404,0x04040400), CONST64(0x04000400,0x04040404), CONST64(0x04000404,0x04040404), + CONST64(0x04040000,0x04040000), CONST64(0x04040004,0x04040000), CONST64(0x04040000,0x04040004), CONST64(0x04040004,0x04040004), + CONST64(0x04040400,0x04040000), CONST64(0x04040404,0x04040000), CONST64(0x04040400,0x04040004), CONST64(0x04040404,0x04040004), + CONST64(0x04040000,0x04040400), CONST64(0x04040004,0x04040400), CONST64(0x04040000,0x04040404), CONST64(0x04040004,0x04040404), + CONST64(0x04040400,0x04040400), CONST64(0x04040404,0x04040400), CONST64(0x04040400,0x04040404), CONST64(0x04040404,0x04040404) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000002,0x00000000), CONST64(0x00000000,0x00000002), CONST64(0x00000002,0x00000002), + CONST64(0x00000200,0x00000000), CONST64(0x00000202,0x00000000), CONST64(0x00000200,0x00000002), CONST64(0x00000202,0x00000002), + CONST64(0x00000000,0x00000200), CONST64(0x00000002,0x00000200), CONST64(0x00000000,0x00000202), CONST64(0x00000002,0x00000202), + CONST64(0x00000200,0x00000200), CONST64(0x00000202,0x00000200), CONST64(0x00000200,0x00000202), CONST64(0x00000202,0x00000202), + CONST64(0x00020000,0x00000000), CONST64(0x00020002,0x00000000), CONST64(0x00020000,0x00000002), CONST64(0x00020002,0x00000002), + CONST64(0x00020200,0x00000000), CONST64(0x00020202,0x00000000), CONST64(0x00020200,0x00000002), CONST64(0x00020202,0x00000002), + CONST64(0x00020000,0x00000200), CONST64(0x00020002,0x00000200), CONST64(0x00020000,0x00000202), CONST64(0x00020002,0x00000202), + CONST64(0x00020200,0x00000200), CONST64(0x00020202,0x00000200), CONST64(0x00020200,0x00000202), CONST64(0x00020202,0x00000202), + CONST64(0x00000000,0x00020000), CONST64(0x00000002,0x00020000), CONST64(0x00000000,0x00020002), CONST64(0x00000002,0x00020002), + CONST64(0x00000200,0x00020000), CONST64(0x00000202,0x00020000), CONST64(0x00000200,0x00020002), CONST64(0x00000202,0x00020002), + CONST64(0x00000000,0x00020200), CONST64(0x00000002,0x00020200), CONST64(0x00000000,0x00020202), CONST64(0x00000002,0x00020202), + CONST64(0x00000200,0x00020200), CONST64(0x00000202,0x00020200), CONST64(0x00000200,0x00020202), CONST64(0x00000202,0x00020202), + CONST64(0x00020000,0x00020000), CONST64(0x00020002,0x00020000), CONST64(0x00020000,0x00020002), CONST64(0x00020002,0x00020002), + CONST64(0x00020200,0x00020000), CONST64(0x00020202,0x00020000), CONST64(0x00020200,0x00020002), CONST64(0x00020202,0x00020002), + CONST64(0x00020000,0x00020200), CONST64(0x00020002,0x00020200), CONST64(0x00020000,0x00020202), CONST64(0x00020002,0x00020202), + CONST64(0x00020200,0x00020200), CONST64(0x00020202,0x00020200), CONST64(0x00020200,0x00020202), CONST64(0x00020202,0x00020202), + CONST64(0x02000000,0x00000000), CONST64(0x02000002,0x00000000), CONST64(0x02000000,0x00000002), CONST64(0x02000002,0x00000002), + CONST64(0x02000200,0x00000000), CONST64(0x02000202,0x00000000), CONST64(0x02000200,0x00000002), CONST64(0x02000202,0x00000002), + CONST64(0x02000000,0x00000200), CONST64(0x02000002,0x00000200), CONST64(0x02000000,0x00000202), CONST64(0x02000002,0x00000202), + CONST64(0x02000200,0x00000200), CONST64(0x02000202,0x00000200), CONST64(0x02000200,0x00000202), CONST64(0x02000202,0x00000202), + CONST64(0x02020000,0x00000000), CONST64(0x02020002,0x00000000), CONST64(0x02020000,0x00000002), CONST64(0x02020002,0x00000002), + CONST64(0x02020200,0x00000000), CONST64(0x02020202,0x00000000), CONST64(0x02020200,0x00000002), CONST64(0x02020202,0x00000002), + CONST64(0x02020000,0x00000200), CONST64(0x02020002,0x00000200), CONST64(0x02020000,0x00000202), CONST64(0x02020002,0x00000202), + CONST64(0x02020200,0x00000200), CONST64(0x02020202,0x00000200), CONST64(0x02020200,0x00000202), CONST64(0x02020202,0x00000202), + CONST64(0x02000000,0x00020000), CONST64(0x02000002,0x00020000), CONST64(0x02000000,0x00020002), CONST64(0x02000002,0x00020002), + CONST64(0x02000200,0x00020000), CONST64(0x02000202,0x00020000), CONST64(0x02000200,0x00020002), CONST64(0x02000202,0x00020002), + CONST64(0x02000000,0x00020200), CONST64(0x02000002,0x00020200), CONST64(0x02000000,0x00020202), CONST64(0x02000002,0x00020202), + CONST64(0x02000200,0x00020200), CONST64(0x02000202,0x00020200), CONST64(0x02000200,0x00020202), CONST64(0x02000202,0x00020202), + CONST64(0x02020000,0x00020000), CONST64(0x02020002,0x00020000), CONST64(0x02020000,0x00020002), CONST64(0x02020002,0x00020002), + CONST64(0x02020200,0x00020000), CONST64(0x02020202,0x00020000), CONST64(0x02020200,0x00020002), CONST64(0x02020202,0x00020002), + CONST64(0x02020000,0x00020200), CONST64(0x02020002,0x00020200), CONST64(0x02020000,0x00020202), CONST64(0x02020002,0x00020202), + CONST64(0x02020200,0x00020200), CONST64(0x02020202,0x00020200), CONST64(0x02020200,0x00020202), CONST64(0x02020202,0x00020202), + CONST64(0x00000000,0x02000000), CONST64(0x00000002,0x02000000), CONST64(0x00000000,0x02000002), CONST64(0x00000002,0x02000002), + CONST64(0x00000200,0x02000000), CONST64(0x00000202,0x02000000), CONST64(0x00000200,0x02000002), CONST64(0x00000202,0x02000002), + CONST64(0x00000000,0x02000200), CONST64(0x00000002,0x02000200), CONST64(0x00000000,0x02000202), CONST64(0x00000002,0x02000202), + CONST64(0x00000200,0x02000200), CONST64(0x00000202,0x02000200), CONST64(0x00000200,0x02000202), CONST64(0x00000202,0x02000202), + CONST64(0x00020000,0x02000000), CONST64(0x00020002,0x02000000), CONST64(0x00020000,0x02000002), CONST64(0x00020002,0x02000002), + CONST64(0x00020200,0x02000000), CONST64(0x00020202,0x02000000), CONST64(0x00020200,0x02000002), CONST64(0x00020202,0x02000002), + CONST64(0x00020000,0x02000200), CONST64(0x00020002,0x02000200), CONST64(0x00020000,0x02000202), CONST64(0x00020002,0x02000202), + CONST64(0x00020200,0x02000200), CONST64(0x00020202,0x02000200), CONST64(0x00020200,0x02000202), CONST64(0x00020202,0x02000202), + CONST64(0x00000000,0x02020000), CONST64(0x00000002,0x02020000), CONST64(0x00000000,0x02020002), CONST64(0x00000002,0x02020002), + CONST64(0x00000200,0x02020000), CONST64(0x00000202,0x02020000), CONST64(0x00000200,0x02020002), CONST64(0x00000202,0x02020002), + CONST64(0x00000000,0x02020200), CONST64(0x00000002,0x02020200), CONST64(0x00000000,0x02020202), CONST64(0x00000002,0x02020202), + CONST64(0x00000200,0x02020200), CONST64(0x00000202,0x02020200), CONST64(0x00000200,0x02020202), CONST64(0x00000202,0x02020202), + CONST64(0x00020000,0x02020000), CONST64(0x00020002,0x02020000), CONST64(0x00020000,0x02020002), CONST64(0x00020002,0x02020002), + CONST64(0x00020200,0x02020000), CONST64(0x00020202,0x02020000), CONST64(0x00020200,0x02020002), CONST64(0x00020202,0x02020002), + CONST64(0x00020000,0x02020200), CONST64(0x00020002,0x02020200), CONST64(0x00020000,0x02020202), CONST64(0x00020002,0x02020202), + CONST64(0x00020200,0x02020200), CONST64(0x00020202,0x02020200), CONST64(0x00020200,0x02020202), CONST64(0x00020202,0x02020202), + CONST64(0x02000000,0x02000000), CONST64(0x02000002,0x02000000), CONST64(0x02000000,0x02000002), CONST64(0x02000002,0x02000002), + CONST64(0x02000200,0x02000000), CONST64(0x02000202,0x02000000), CONST64(0x02000200,0x02000002), CONST64(0x02000202,0x02000002), + CONST64(0x02000000,0x02000200), CONST64(0x02000002,0x02000200), CONST64(0x02000000,0x02000202), CONST64(0x02000002,0x02000202), + CONST64(0x02000200,0x02000200), CONST64(0x02000202,0x02000200), CONST64(0x02000200,0x02000202), CONST64(0x02000202,0x02000202), + CONST64(0x02020000,0x02000000), CONST64(0x02020002,0x02000000), CONST64(0x02020000,0x02000002), CONST64(0x02020002,0x02000002), + CONST64(0x02020200,0x02000000), CONST64(0x02020202,0x02000000), CONST64(0x02020200,0x02000002), CONST64(0x02020202,0x02000002), + CONST64(0x02020000,0x02000200), CONST64(0x02020002,0x02000200), CONST64(0x02020000,0x02000202), CONST64(0x02020002,0x02000202), + CONST64(0x02020200,0x02000200), CONST64(0x02020202,0x02000200), CONST64(0x02020200,0x02000202), CONST64(0x02020202,0x02000202), + CONST64(0x02000000,0x02020000), CONST64(0x02000002,0x02020000), CONST64(0x02000000,0x02020002), CONST64(0x02000002,0x02020002), + CONST64(0x02000200,0x02020000), CONST64(0x02000202,0x02020000), CONST64(0x02000200,0x02020002), CONST64(0x02000202,0x02020002), + CONST64(0x02000000,0x02020200), CONST64(0x02000002,0x02020200), CONST64(0x02000000,0x02020202), CONST64(0x02000002,0x02020202), + CONST64(0x02000200,0x02020200), CONST64(0x02000202,0x02020200), CONST64(0x02000200,0x02020202), CONST64(0x02000202,0x02020202), + CONST64(0x02020000,0x02020000), CONST64(0x02020002,0x02020000), CONST64(0x02020000,0x02020002), CONST64(0x02020002,0x02020002), + CONST64(0x02020200,0x02020000), CONST64(0x02020202,0x02020000), CONST64(0x02020200,0x02020002), CONST64(0x02020202,0x02020002), + CONST64(0x02020000,0x02020200), CONST64(0x02020002,0x02020200), CONST64(0x02020000,0x02020202), CONST64(0x02020002,0x02020202), + CONST64(0x02020200,0x02020200), CONST64(0x02020202,0x02020200), CONST64(0x02020200,0x02020202), CONST64(0x02020202,0x02020202) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000100,0x00000000), CONST64(0x00000000,0x00000100), CONST64(0x00000100,0x00000100), + CONST64(0x00010000,0x00000000), CONST64(0x00010100,0x00000000), CONST64(0x00010000,0x00000100), CONST64(0x00010100,0x00000100), + CONST64(0x00000000,0x00010000), CONST64(0x00000100,0x00010000), CONST64(0x00000000,0x00010100), CONST64(0x00000100,0x00010100), + CONST64(0x00010000,0x00010000), CONST64(0x00010100,0x00010000), CONST64(0x00010000,0x00010100), CONST64(0x00010100,0x00010100), + CONST64(0x01000000,0x00000000), CONST64(0x01000100,0x00000000), CONST64(0x01000000,0x00000100), CONST64(0x01000100,0x00000100), + CONST64(0x01010000,0x00000000), CONST64(0x01010100,0x00000000), CONST64(0x01010000,0x00000100), CONST64(0x01010100,0x00000100), + CONST64(0x01000000,0x00010000), CONST64(0x01000100,0x00010000), CONST64(0x01000000,0x00010100), CONST64(0x01000100,0x00010100), + CONST64(0x01010000,0x00010000), CONST64(0x01010100,0x00010000), CONST64(0x01010000,0x00010100), CONST64(0x01010100,0x00010100), + CONST64(0x00000000,0x01000000), CONST64(0x00000100,0x01000000), CONST64(0x00000000,0x01000100), CONST64(0x00000100,0x01000100), + CONST64(0x00010000,0x01000000), CONST64(0x00010100,0x01000000), CONST64(0x00010000,0x01000100), CONST64(0x00010100,0x01000100), + CONST64(0x00000000,0x01010000), CONST64(0x00000100,0x01010000), CONST64(0x00000000,0x01010100), CONST64(0x00000100,0x01010100), + CONST64(0x00010000,0x01010000), CONST64(0x00010100,0x01010000), CONST64(0x00010000,0x01010100), CONST64(0x00010100,0x01010100), + CONST64(0x01000000,0x01000000), CONST64(0x01000100,0x01000000), CONST64(0x01000000,0x01000100), CONST64(0x01000100,0x01000100), + CONST64(0x01010000,0x01000000), CONST64(0x01010100,0x01000000), CONST64(0x01010000,0x01000100), CONST64(0x01010100,0x01000100), + CONST64(0x01000000,0x01010000), CONST64(0x01000100,0x01010000), CONST64(0x01000000,0x01010100), CONST64(0x01000100,0x01010100), + CONST64(0x01010000,0x01010000), CONST64(0x01010100,0x01010000), CONST64(0x01010000,0x01010100), CONST64(0x01010100,0x01010100), + CONST64(0x00000001,0x00000000), CONST64(0x00000101,0x00000000), CONST64(0x00000001,0x00000100), CONST64(0x00000101,0x00000100), + CONST64(0x00010001,0x00000000), CONST64(0x00010101,0x00000000), CONST64(0x00010001,0x00000100), CONST64(0x00010101,0x00000100), + CONST64(0x00000001,0x00010000), CONST64(0x00000101,0x00010000), CONST64(0x00000001,0x00010100), CONST64(0x00000101,0x00010100), + CONST64(0x00010001,0x00010000), CONST64(0x00010101,0x00010000), CONST64(0x00010001,0x00010100), CONST64(0x00010101,0x00010100), + CONST64(0x01000001,0x00000000), CONST64(0x01000101,0x00000000), CONST64(0x01000001,0x00000100), CONST64(0x01000101,0x00000100), + CONST64(0x01010001,0x00000000), CONST64(0x01010101,0x00000000), CONST64(0x01010001,0x00000100), CONST64(0x01010101,0x00000100), + CONST64(0x01000001,0x00010000), CONST64(0x01000101,0x00010000), CONST64(0x01000001,0x00010100), CONST64(0x01000101,0x00010100), + CONST64(0x01010001,0x00010000), CONST64(0x01010101,0x00010000), CONST64(0x01010001,0x00010100), CONST64(0x01010101,0x00010100), + CONST64(0x00000001,0x01000000), CONST64(0x00000101,0x01000000), CONST64(0x00000001,0x01000100), CONST64(0x00000101,0x01000100), + CONST64(0x00010001,0x01000000), CONST64(0x00010101,0x01000000), CONST64(0x00010001,0x01000100), CONST64(0x00010101,0x01000100), + CONST64(0x00000001,0x01010000), CONST64(0x00000101,0x01010000), CONST64(0x00000001,0x01010100), CONST64(0x00000101,0x01010100), + CONST64(0x00010001,0x01010000), CONST64(0x00010101,0x01010000), CONST64(0x00010001,0x01010100), CONST64(0x00010101,0x01010100), + CONST64(0x01000001,0x01000000), CONST64(0x01000101,0x01000000), CONST64(0x01000001,0x01000100), CONST64(0x01000101,0x01000100), + CONST64(0x01010001,0x01000000), CONST64(0x01010101,0x01000000), CONST64(0x01010001,0x01000100), CONST64(0x01010101,0x01000100), + CONST64(0x01000001,0x01010000), CONST64(0x01000101,0x01010000), CONST64(0x01000001,0x01010100), CONST64(0x01000101,0x01010100), + CONST64(0x01010001,0x01010000), CONST64(0x01010101,0x01010000), CONST64(0x01010001,0x01010100), CONST64(0x01010101,0x01010100), + CONST64(0x00000000,0x00000001), CONST64(0x00000100,0x00000001), CONST64(0x00000000,0x00000101), CONST64(0x00000100,0x00000101), + CONST64(0x00010000,0x00000001), CONST64(0x00010100,0x00000001), CONST64(0x00010000,0x00000101), CONST64(0x00010100,0x00000101), + CONST64(0x00000000,0x00010001), CONST64(0x00000100,0x00010001), CONST64(0x00000000,0x00010101), CONST64(0x00000100,0x00010101), + CONST64(0x00010000,0x00010001), CONST64(0x00010100,0x00010001), CONST64(0x00010000,0x00010101), CONST64(0x00010100,0x00010101), + CONST64(0x01000000,0x00000001), CONST64(0x01000100,0x00000001), CONST64(0x01000000,0x00000101), CONST64(0x01000100,0x00000101), + CONST64(0x01010000,0x00000001), CONST64(0x01010100,0x00000001), CONST64(0x01010000,0x00000101), CONST64(0x01010100,0x00000101), + CONST64(0x01000000,0x00010001), CONST64(0x01000100,0x00010001), CONST64(0x01000000,0x00010101), CONST64(0x01000100,0x00010101), + CONST64(0x01010000,0x00010001), CONST64(0x01010100,0x00010001), CONST64(0x01010000,0x00010101), CONST64(0x01010100,0x00010101), + CONST64(0x00000000,0x01000001), CONST64(0x00000100,0x01000001), CONST64(0x00000000,0x01000101), CONST64(0x00000100,0x01000101), + CONST64(0x00010000,0x01000001), CONST64(0x00010100,0x01000001), CONST64(0x00010000,0x01000101), CONST64(0x00010100,0x01000101), + CONST64(0x00000000,0x01010001), CONST64(0x00000100,0x01010001), CONST64(0x00000000,0x01010101), CONST64(0x00000100,0x01010101), + CONST64(0x00010000,0x01010001), CONST64(0x00010100,0x01010001), CONST64(0x00010000,0x01010101), CONST64(0x00010100,0x01010101), + CONST64(0x01000000,0x01000001), CONST64(0x01000100,0x01000001), CONST64(0x01000000,0x01000101), CONST64(0x01000100,0x01000101), + CONST64(0x01010000,0x01000001), CONST64(0x01010100,0x01000001), CONST64(0x01010000,0x01000101), CONST64(0x01010100,0x01000101), + CONST64(0x01000000,0x01010001), CONST64(0x01000100,0x01010001), CONST64(0x01000000,0x01010101), CONST64(0x01000100,0x01010101), + CONST64(0x01010000,0x01010001), CONST64(0x01010100,0x01010001), CONST64(0x01010000,0x01010101), CONST64(0x01010100,0x01010101), + CONST64(0x00000001,0x00000001), CONST64(0x00000101,0x00000001), CONST64(0x00000001,0x00000101), CONST64(0x00000101,0x00000101), + CONST64(0x00010001,0x00000001), CONST64(0x00010101,0x00000001), CONST64(0x00010001,0x00000101), CONST64(0x00010101,0x00000101), + CONST64(0x00000001,0x00010001), CONST64(0x00000101,0x00010001), CONST64(0x00000001,0x00010101), CONST64(0x00000101,0x00010101), + CONST64(0x00010001,0x00010001), CONST64(0x00010101,0x00010001), CONST64(0x00010001,0x00010101), CONST64(0x00010101,0x00010101), + CONST64(0x01000001,0x00000001), CONST64(0x01000101,0x00000001), CONST64(0x01000001,0x00000101), CONST64(0x01000101,0x00000101), + CONST64(0x01010001,0x00000001), CONST64(0x01010101,0x00000001), CONST64(0x01010001,0x00000101), CONST64(0x01010101,0x00000101), + CONST64(0x01000001,0x00010001), CONST64(0x01000101,0x00010001), CONST64(0x01000001,0x00010101), CONST64(0x01000101,0x00010101), + CONST64(0x01010001,0x00010001), CONST64(0x01010101,0x00010001), CONST64(0x01010001,0x00010101), CONST64(0x01010101,0x00010101), + CONST64(0x00000001,0x01000001), CONST64(0x00000101,0x01000001), CONST64(0x00000001,0x01000101), CONST64(0x00000101,0x01000101), + CONST64(0x00010001,0x01000001), CONST64(0x00010101,0x01000001), CONST64(0x00010001,0x01000101), CONST64(0x00010101,0x01000101), + CONST64(0x00000001,0x01010001), CONST64(0x00000101,0x01010001), CONST64(0x00000001,0x01010101), CONST64(0x00000101,0x01010101), + CONST64(0x00010001,0x01010001), CONST64(0x00010101,0x01010001), CONST64(0x00010001,0x01010101), CONST64(0x00010101,0x01010101), + CONST64(0x01000001,0x01000001), CONST64(0x01000101,0x01000001), CONST64(0x01000001,0x01000101), CONST64(0x01000101,0x01000101), + CONST64(0x01010001,0x01000001), CONST64(0x01010101,0x01000001), CONST64(0x01010001,0x01000101), CONST64(0x01010101,0x01000101), + CONST64(0x01000001,0x01010001), CONST64(0x01000101,0x01010001), CONST64(0x01000001,0x01010101), CONST64(0x01000101,0x01010101), + CONST64(0x01010001,0x01010001), CONST64(0x01010101,0x01010001), CONST64(0x01010001,0x01010101), CONST64(0x01010101,0x01010101) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000080,0x00000000), CONST64(0x00000000,0x00000080), CONST64(0x00000080,0x00000080), + CONST64(0x00008000,0x00000000), CONST64(0x00008080,0x00000000), CONST64(0x00008000,0x00000080), CONST64(0x00008080,0x00000080), + CONST64(0x00000000,0x00008000), CONST64(0x00000080,0x00008000), CONST64(0x00000000,0x00008080), CONST64(0x00000080,0x00008080), + CONST64(0x00008000,0x00008000), CONST64(0x00008080,0x00008000), CONST64(0x00008000,0x00008080), CONST64(0x00008080,0x00008080), + CONST64(0x00800000,0x00000000), CONST64(0x00800080,0x00000000), CONST64(0x00800000,0x00000080), CONST64(0x00800080,0x00000080), + CONST64(0x00808000,0x00000000), CONST64(0x00808080,0x00000000), CONST64(0x00808000,0x00000080), CONST64(0x00808080,0x00000080), + CONST64(0x00800000,0x00008000), CONST64(0x00800080,0x00008000), CONST64(0x00800000,0x00008080), CONST64(0x00800080,0x00008080), + CONST64(0x00808000,0x00008000), CONST64(0x00808080,0x00008000), CONST64(0x00808000,0x00008080), CONST64(0x00808080,0x00008080), + CONST64(0x00000000,0x00800000), CONST64(0x00000080,0x00800000), CONST64(0x00000000,0x00800080), CONST64(0x00000080,0x00800080), + CONST64(0x00008000,0x00800000), CONST64(0x00008080,0x00800000), CONST64(0x00008000,0x00800080), CONST64(0x00008080,0x00800080), + CONST64(0x00000000,0x00808000), CONST64(0x00000080,0x00808000), CONST64(0x00000000,0x00808080), CONST64(0x00000080,0x00808080), + CONST64(0x00008000,0x00808000), CONST64(0x00008080,0x00808000), CONST64(0x00008000,0x00808080), CONST64(0x00008080,0x00808080), + CONST64(0x00800000,0x00800000), CONST64(0x00800080,0x00800000), CONST64(0x00800000,0x00800080), CONST64(0x00800080,0x00800080), + CONST64(0x00808000,0x00800000), CONST64(0x00808080,0x00800000), CONST64(0x00808000,0x00800080), CONST64(0x00808080,0x00800080), + CONST64(0x00800000,0x00808000), CONST64(0x00800080,0x00808000), CONST64(0x00800000,0x00808080), CONST64(0x00800080,0x00808080), + CONST64(0x00808000,0x00808000), CONST64(0x00808080,0x00808000), CONST64(0x00808000,0x00808080), CONST64(0x00808080,0x00808080), + CONST64(0x80000000,0x00000000), CONST64(0x80000080,0x00000000), CONST64(0x80000000,0x00000080), CONST64(0x80000080,0x00000080), + CONST64(0x80008000,0x00000000), CONST64(0x80008080,0x00000000), CONST64(0x80008000,0x00000080), CONST64(0x80008080,0x00000080), + CONST64(0x80000000,0x00008000), CONST64(0x80000080,0x00008000), CONST64(0x80000000,0x00008080), CONST64(0x80000080,0x00008080), + CONST64(0x80008000,0x00008000), CONST64(0x80008080,0x00008000), CONST64(0x80008000,0x00008080), CONST64(0x80008080,0x00008080), + CONST64(0x80800000,0x00000000), CONST64(0x80800080,0x00000000), CONST64(0x80800000,0x00000080), CONST64(0x80800080,0x00000080), + CONST64(0x80808000,0x00000000), CONST64(0x80808080,0x00000000), CONST64(0x80808000,0x00000080), CONST64(0x80808080,0x00000080), + CONST64(0x80800000,0x00008000), CONST64(0x80800080,0x00008000), CONST64(0x80800000,0x00008080), CONST64(0x80800080,0x00008080), + CONST64(0x80808000,0x00008000), CONST64(0x80808080,0x00008000), CONST64(0x80808000,0x00008080), CONST64(0x80808080,0x00008080), + CONST64(0x80000000,0x00800000), CONST64(0x80000080,0x00800000), CONST64(0x80000000,0x00800080), CONST64(0x80000080,0x00800080), + CONST64(0x80008000,0x00800000), CONST64(0x80008080,0x00800000), CONST64(0x80008000,0x00800080), CONST64(0x80008080,0x00800080), + CONST64(0x80000000,0x00808000), CONST64(0x80000080,0x00808000), CONST64(0x80000000,0x00808080), CONST64(0x80000080,0x00808080), + CONST64(0x80008000,0x00808000), CONST64(0x80008080,0x00808000), CONST64(0x80008000,0x00808080), CONST64(0x80008080,0x00808080), + CONST64(0x80800000,0x00800000), CONST64(0x80800080,0x00800000), CONST64(0x80800000,0x00800080), CONST64(0x80800080,0x00800080), + CONST64(0x80808000,0x00800000), CONST64(0x80808080,0x00800000), CONST64(0x80808000,0x00800080), CONST64(0x80808080,0x00800080), + CONST64(0x80800000,0x00808000), CONST64(0x80800080,0x00808000), CONST64(0x80800000,0x00808080), CONST64(0x80800080,0x00808080), + CONST64(0x80808000,0x00808000), CONST64(0x80808080,0x00808000), CONST64(0x80808000,0x00808080), CONST64(0x80808080,0x00808080), + CONST64(0x00000000,0x80000000), CONST64(0x00000080,0x80000000), CONST64(0x00000000,0x80000080), CONST64(0x00000080,0x80000080), + CONST64(0x00008000,0x80000000), CONST64(0x00008080,0x80000000), CONST64(0x00008000,0x80000080), CONST64(0x00008080,0x80000080), + CONST64(0x00000000,0x80008000), CONST64(0x00000080,0x80008000), CONST64(0x00000000,0x80008080), CONST64(0x00000080,0x80008080), + CONST64(0x00008000,0x80008000), CONST64(0x00008080,0x80008000), CONST64(0x00008000,0x80008080), CONST64(0x00008080,0x80008080), + CONST64(0x00800000,0x80000000), CONST64(0x00800080,0x80000000), CONST64(0x00800000,0x80000080), CONST64(0x00800080,0x80000080), + CONST64(0x00808000,0x80000000), CONST64(0x00808080,0x80000000), CONST64(0x00808000,0x80000080), CONST64(0x00808080,0x80000080), + CONST64(0x00800000,0x80008000), CONST64(0x00800080,0x80008000), CONST64(0x00800000,0x80008080), CONST64(0x00800080,0x80008080), + CONST64(0x00808000,0x80008000), CONST64(0x00808080,0x80008000), CONST64(0x00808000,0x80008080), CONST64(0x00808080,0x80008080), + CONST64(0x00000000,0x80800000), CONST64(0x00000080,0x80800000), CONST64(0x00000000,0x80800080), CONST64(0x00000080,0x80800080), + CONST64(0x00008000,0x80800000), CONST64(0x00008080,0x80800000), CONST64(0x00008000,0x80800080), CONST64(0x00008080,0x80800080), + CONST64(0x00000000,0x80808000), CONST64(0x00000080,0x80808000), CONST64(0x00000000,0x80808080), CONST64(0x00000080,0x80808080), + CONST64(0x00008000,0x80808000), CONST64(0x00008080,0x80808000), CONST64(0x00008000,0x80808080), CONST64(0x00008080,0x80808080), + CONST64(0x00800000,0x80800000), CONST64(0x00800080,0x80800000), CONST64(0x00800000,0x80800080), CONST64(0x00800080,0x80800080), + CONST64(0x00808000,0x80800000), CONST64(0x00808080,0x80800000), CONST64(0x00808000,0x80800080), CONST64(0x00808080,0x80800080), + CONST64(0x00800000,0x80808000), CONST64(0x00800080,0x80808000), CONST64(0x00800000,0x80808080), CONST64(0x00800080,0x80808080), + CONST64(0x00808000,0x80808000), CONST64(0x00808080,0x80808000), CONST64(0x00808000,0x80808080), CONST64(0x00808080,0x80808080), + CONST64(0x80000000,0x80000000), CONST64(0x80000080,0x80000000), CONST64(0x80000000,0x80000080), CONST64(0x80000080,0x80000080), + CONST64(0x80008000,0x80000000), CONST64(0x80008080,0x80000000), CONST64(0x80008000,0x80000080), CONST64(0x80008080,0x80000080), + CONST64(0x80000000,0x80008000), CONST64(0x80000080,0x80008000), CONST64(0x80000000,0x80008080), CONST64(0x80000080,0x80008080), + CONST64(0x80008000,0x80008000), CONST64(0x80008080,0x80008000), CONST64(0x80008000,0x80008080), CONST64(0x80008080,0x80008080), + CONST64(0x80800000,0x80000000), CONST64(0x80800080,0x80000000), CONST64(0x80800000,0x80000080), CONST64(0x80800080,0x80000080), + CONST64(0x80808000,0x80000000), CONST64(0x80808080,0x80000000), CONST64(0x80808000,0x80000080), CONST64(0x80808080,0x80000080), + CONST64(0x80800000,0x80008000), CONST64(0x80800080,0x80008000), CONST64(0x80800000,0x80008080), CONST64(0x80800080,0x80008080), + CONST64(0x80808000,0x80008000), CONST64(0x80808080,0x80008000), CONST64(0x80808000,0x80008080), CONST64(0x80808080,0x80008080), + CONST64(0x80000000,0x80800000), CONST64(0x80000080,0x80800000), CONST64(0x80000000,0x80800080), CONST64(0x80000080,0x80800080), + CONST64(0x80008000,0x80800000), CONST64(0x80008080,0x80800000), CONST64(0x80008000,0x80800080), CONST64(0x80008080,0x80800080), + CONST64(0x80000000,0x80808000), CONST64(0x80000080,0x80808000), CONST64(0x80000000,0x80808080), CONST64(0x80000080,0x80808080), + CONST64(0x80008000,0x80808000), CONST64(0x80008080,0x80808000), CONST64(0x80008000,0x80808080), CONST64(0x80008080,0x80808080), + CONST64(0x80800000,0x80800000), CONST64(0x80800080,0x80800000), CONST64(0x80800000,0x80800080), CONST64(0x80800080,0x80800080), + CONST64(0x80808000,0x80800000), CONST64(0x80808080,0x80800000), CONST64(0x80808000,0x80800080), CONST64(0x80808080,0x80800080), + CONST64(0x80800000,0x80808000), CONST64(0x80800080,0x80808000), CONST64(0x80800000,0x80808080), CONST64(0x80800080,0x80808080), + CONST64(0x80808000,0x80808000), CONST64(0x80808080,0x80808000), CONST64(0x80808000,0x80808080), CONST64(0x80808080,0x80808080) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000040,0x00000000), CONST64(0x00000000,0x00000040), CONST64(0x00000040,0x00000040), + CONST64(0x00004000,0x00000000), CONST64(0x00004040,0x00000000), CONST64(0x00004000,0x00000040), CONST64(0x00004040,0x00000040), + CONST64(0x00000000,0x00004000), CONST64(0x00000040,0x00004000), CONST64(0x00000000,0x00004040), CONST64(0x00000040,0x00004040), + CONST64(0x00004000,0x00004000), CONST64(0x00004040,0x00004000), CONST64(0x00004000,0x00004040), CONST64(0x00004040,0x00004040), + CONST64(0x00400000,0x00000000), CONST64(0x00400040,0x00000000), CONST64(0x00400000,0x00000040), CONST64(0x00400040,0x00000040), + CONST64(0x00404000,0x00000000), CONST64(0x00404040,0x00000000), CONST64(0x00404000,0x00000040), CONST64(0x00404040,0x00000040), + CONST64(0x00400000,0x00004000), CONST64(0x00400040,0x00004000), CONST64(0x00400000,0x00004040), CONST64(0x00400040,0x00004040), + CONST64(0x00404000,0x00004000), CONST64(0x00404040,0x00004000), CONST64(0x00404000,0x00004040), CONST64(0x00404040,0x00004040), + CONST64(0x00000000,0x00400000), CONST64(0x00000040,0x00400000), CONST64(0x00000000,0x00400040), CONST64(0x00000040,0x00400040), + CONST64(0x00004000,0x00400000), CONST64(0x00004040,0x00400000), CONST64(0x00004000,0x00400040), CONST64(0x00004040,0x00400040), + CONST64(0x00000000,0x00404000), CONST64(0x00000040,0x00404000), CONST64(0x00000000,0x00404040), CONST64(0x00000040,0x00404040), + CONST64(0x00004000,0x00404000), CONST64(0x00004040,0x00404000), CONST64(0x00004000,0x00404040), CONST64(0x00004040,0x00404040), + CONST64(0x00400000,0x00400000), CONST64(0x00400040,0x00400000), CONST64(0x00400000,0x00400040), CONST64(0x00400040,0x00400040), + CONST64(0x00404000,0x00400000), CONST64(0x00404040,0x00400000), CONST64(0x00404000,0x00400040), CONST64(0x00404040,0x00400040), + CONST64(0x00400000,0x00404000), CONST64(0x00400040,0x00404000), CONST64(0x00400000,0x00404040), CONST64(0x00400040,0x00404040), + CONST64(0x00404000,0x00404000), CONST64(0x00404040,0x00404000), CONST64(0x00404000,0x00404040), CONST64(0x00404040,0x00404040), + CONST64(0x40000000,0x00000000), CONST64(0x40000040,0x00000000), CONST64(0x40000000,0x00000040), CONST64(0x40000040,0x00000040), + CONST64(0x40004000,0x00000000), CONST64(0x40004040,0x00000000), CONST64(0x40004000,0x00000040), CONST64(0x40004040,0x00000040), + CONST64(0x40000000,0x00004000), CONST64(0x40000040,0x00004000), CONST64(0x40000000,0x00004040), CONST64(0x40000040,0x00004040), + CONST64(0x40004000,0x00004000), CONST64(0x40004040,0x00004000), CONST64(0x40004000,0x00004040), CONST64(0x40004040,0x00004040), + CONST64(0x40400000,0x00000000), CONST64(0x40400040,0x00000000), CONST64(0x40400000,0x00000040), CONST64(0x40400040,0x00000040), + CONST64(0x40404000,0x00000000), CONST64(0x40404040,0x00000000), CONST64(0x40404000,0x00000040), CONST64(0x40404040,0x00000040), + CONST64(0x40400000,0x00004000), CONST64(0x40400040,0x00004000), CONST64(0x40400000,0x00004040), CONST64(0x40400040,0x00004040), + CONST64(0x40404000,0x00004000), CONST64(0x40404040,0x00004000), CONST64(0x40404000,0x00004040), CONST64(0x40404040,0x00004040), + CONST64(0x40000000,0x00400000), CONST64(0x40000040,0x00400000), CONST64(0x40000000,0x00400040), CONST64(0x40000040,0x00400040), + CONST64(0x40004000,0x00400000), CONST64(0x40004040,0x00400000), CONST64(0x40004000,0x00400040), CONST64(0x40004040,0x00400040), + CONST64(0x40000000,0x00404000), CONST64(0x40000040,0x00404000), CONST64(0x40000000,0x00404040), CONST64(0x40000040,0x00404040), + CONST64(0x40004000,0x00404000), CONST64(0x40004040,0x00404000), CONST64(0x40004000,0x00404040), CONST64(0x40004040,0x00404040), + CONST64(0x40400000,0x00400000), CONST64(0x40400040,0x00400000), CONST64(0x40400000,0x00400040), CONST64(0x40400040,0x00400040), + CONST64(0x40404000,0x00400000), CONST64(0x40404040,0x00400000), CONST64(0x40404000,0x00400040), CONST64(0x40404040,0x00400040), + CONST64(0x40400000,0x00404000), CONST64(0x40400040,0x00404000), CONST64(0x40400000,0x00404040), CONST64(0x40400040,0x00404040), + CONST64(0x40404000,0x00404000), CONST64(0x40404040,0x00404000), CONST64(0x40404000,0x00404040), CONST64(0x40404040,0x00404040), + CONST64(0x00000000,0x40000000), CONST64(0x00000040,0x40000000), CONST64(0x00000000,0x40000040), CONST64(0x00000040,0x40000040), + CONST64(0x00004000,0x40000000), CONST64(0x00004040,0x40000000), CONST64(0x00004000,0x40000040), CONST64(0x00004040,0x40000040), + CONST64(0x00000000,0x40004000), CONST64(0x00000040,0x40004000), CONST64(0x00000000,0x40004040), CONST64(0x00000040,0x40004040), + CONST64(0x00004000,0x40004000), CONST64(0x00004040,0x40004000), CONST64(0x00004000,0x40004040), CONST64(0x00004040,0x40004040), + CONST64(0x00400000,0x40000000), CONST64(0x00400040,0x40000000), CONST64(0x00400000,0x40000040), CONST64(0x00400040,0x40000040), + CONST64(0x00404000,0x40000000), CONST64(0x00404040,0x40000000), CONST64(0x00404000,0x40000040), CONST64(0x00404040,0x40000040), + CONST64(0x00400000,0x40004000), CONST64(0x00400040,0x40004000), CONST64(0x00400000,0x40004040), CONST64(0x00400040,0x40004040), + CONST64(0x00404000,0x40004000), CONST64(0x00404040,0x40004000), CONST64(0x00404000,0x40004040), CONST64(0x00404040,0x40004040), + CONST64(0x00000000,0x40400000), CONST64(0x00000040,0x40400000), CONST64(0x00000000,0x40400040), CONST64(0x00000040,0x40400040), + CONST64(0x00004000,0x40400000), CONST64(0x00004040,0x40400000), CONST64(0x00004000,0x40400040), CONST64(0x00004040,0x40400040), + CONST64(0x00000000,0x40404000), CONST64(0x00000040,0x40404000), CONST64(0x00000000,0x40404040), CONST64(0x00000040,0x40404040), + CONST64(0x00004000,0x40404000), CONST64(0x00004040,0x40404000), CONST64(0x00004000,0x40404040), CONST64(0x00004040,0x40404040), + CONST64(0x00400000,0x40400000), CONST64(0x00400040,0x40400000), CONST64(0x00400000,0x40400040), CONST64(0x00400040,0x40400040), + CONST64(0x00404000,0x40400000), CONST64(0x00404040,0x40400000), CONST64(0x00404000,0x40400040), CONST64(0x00404040,0x40400040), + CONST64(0x00400000,0x40404000), CONST64(0x00400040,0x40404000), CONST64(0x00400000,0x40404040), CONST64(0x00400040,0x40404040), + CONST64(0x00404000,0x40404000), CONST64(0x00404040,0x40404000), CONST64(0x00404000,0x40404040), CONST64(0x00404040,0x40404040), + CONST64(0x40000000,0x40000000), CONST64(0x40000040,0x40000000), CONST64(0x40000000,0x40000040), CONST64(0x40000040,0x40000040), + CONST64(0x40004000,0x40000000), CONST64(0x40004040,0x40000000), CONST64(0x40004000,0x40000040), CONST64(0x40004040,0x40000040), + CONST64(0x40000000,0x40004000), CONST64(0x40000040,0x40004000), CONST64(0x40000000,0x40004040), CONST64(0x40000040,0x40004040), + CONST64(0x40004000,0x40004000), CONST64(0x40004040,0x40004000), CONST64(0x40004000,0x40004040), CONST64(0x40004040,0x40004040), + CONST64(0x40400000,0x40000000), CONST64(0x40400040,0x40000000), CONST64(0x40400000,0x40000040), CONST64(0x40400040,0x40000040), + CONST64(0x40404000,0x40000000), CONST64(0x40404040,0x40000000), CONST64(0x40404000,0x40000040), CONST64(0x40404040,0x40000040), + CONST64(0x40400000,0x40004000), CONST64(0x40400040,0x40004000), CONST64(0x40400000,0x40004040), CONST64(0x40400040,0x40004040), + CONST64(0x40404000,0x40004000), CONST64(0x40404040,0x40004000), CONST64(0x40404000,0x40004040), CONST64(0x40404040,0x40004040), + CONST64(0x40000000,0x40400000), CONST64(0x40000040,0x40400000), CONST64(0x40000000,0x40400040), CONST64(0x40000040,0x40400040), + CONST64(0x40004000,0x40400000), CONST64(0x40004040,0x40400000), CONST64(0x40004000,0x40400040), CONST64(0x40004040,0x40400040), + CONST64(0x40000000,0x40404000), CONST64(0x40000040,0x40404000), CONST64(0x40000000,0x40404040), CONST64(0x40000040,0x40404040), + CONST64(0x40004000,0x40404000), CONST64(0x40004040,0x40404000), CONST64(0x40004000,0x40404040), CONST64(0x40004040,0x40404040), + CONST64(0x40400000,0x40400000), CONST64(0x40400040,0x40400000), CONST64(0x40400000,0x40400040), CONST64(0x40400040,0x40400040), + CONST64(0x40404000,0x40400000), CONST64(0x40404040,0x40400000), CONST64(0x40404000,0x40400040), CONST64(0x40404040,0x40400040), + CONST64(0x40400000,0x40404000), CONST64(0x40400040,0x40404000), CONST64(0x40400000,0x40404040), CONST64(0x40400040,0x40404040), + CONST64(0x40404000,0x40404000), CONST64(0x40404040,0x40404000), CONST64(0x40404000,0x40404040), CONST64(0x40404040,0x40404040) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000020,0x00000000), CONST64(0x00000000,0x00000020), CONST64(0x00000020,0x00000020), + CONST64(0x00002000,0x00000000), CONST64(0x00002020,0x00000000), CONST64(0x00002000,0x00000020), CONST64(0x00002020,0x00000020), + CONST64(0x00000000,0x00002000), CONST64(0x00000020,0x00002000), CONST64(0x00000000,0x00002020), CONST64(0x00000020,0x00002020), + CONST64(0x00002000,0x00002000), CONST64(0x00002020,0x00002000), CONST64(0x00002000,0x00002020), CONST64(0x00002020,0x00002020), + CONST64(0x00200000,0x00000000), CONST64(0x00200020,0x00000000), CONST64(0x00200000,0x00000020), CONST64(0x00200020,0x00000020), + CONST64(0x00202000,0x00000000), CONST64(0x00202020,0x00000000), CONST64(0x00202000,0x00000020), CONST64(0x00202020,0x00000020), + CONST64(0x00200000,0x00002000), CONST64(0x00200020,0x00002000), CONST64(0x00200000,0x00002020), CONST64(0x00200020,0x00002020), + CONST64(0x00202000,0x00002000), CONST64(0x00202020,0x00002000), CONST64(0x00202000,0x00002020), CONST64(0x00202020,0x00002020), + CONST64(0x00000000,0x00200000), CONST64(0x00000020,0x00200000), CONST64(0x00000000,0x00200020), CONST64(0x00000020,0x00200020), + CONST64(0x00002000,0x00200000), CONST64(0x00002020,0x00200000), CONST64(0x00002000,0x00200020), CONST64(0x00002020,0x00200020), + CONST64(0x00000000,0x00202000), CONST64(0x00000020,0x00202000), CONST64(0x00000000,0x00202020), CONST64(0x00000020,0x00202020), + CONST64(0x00002000,0x00202000), CONST64(0x00002020,0x00202000), CONST64(0x00002000,0x00202020), CONST64(0x00002020,0x00202020), + CONST64(0x00200000,0x00200000), CONST64(0x00200020,0x00200000), CONST64(0x00200000,0x00200020), CONST64(0x00200020,0x00200020), + CONST64(0x00202000,0x00200000), CONST64(0x00202020,0x00200000), CONST64(0x00202000,0x00200020), CONST64(0x00202020,0x00200020), + CONST64(0x00200000,0x00202000), CONST64(0x00200020,0x00202000), CONST64(0x00200000,0x00202020), CONST64(0x00200020,0x00202020), + CONST64(0x00202000,0x00202000), CONST64(0x00202020,0x00202000), CONST64(0x00202000,0x00202020), CONST64(0x00202020,0x00202020), + CONST64(0x20000000,0x00000000), CONST64(0x20000020,0x00000000), CONST64(0x20000000,0x00000020), CONST64(0x20000020,0x00000020), + CONST64(0x20002000,0x00000000), CONST64(0x20002020,0x00000000), CONST64(0x20002000,0x00000020), CONST64(0x20002020,0x00000020), + CONST64(0x20000000,0x00002000), CONST64(0x20000020,0x00002000), CONST64(0x20000000,0x00002020), CONST64(0x20000020,0x00002020), + CONST64(0x20002000,0x00002000), CONST64(0x20002020,0x00002000), CONST64(0x20002000,0x00002020), CONST64(0x20002020,0x00002020), + CONST64(0x20200000,0x00000000), CONST64(0x20200020,0x00000000), CONST64(0x20200000,0x00000020), CONST64(0x20200020,0x00000020), + CONST64(0x20202000,0x00000000), CONST64(0x20202020,0x00000000), CONST64(0x20202000,0x00000020), CONST64(0x20202020,0x00000020), + CONST64(0x20200000,0x00002000), CONST64(0x20200020,0x00002000), CONST64(0x20200000,0x00002020), CONST64(0x20200020,0x00002020), + CONST64(0x20202000,0x00002000), CONST64(0x20202020,0x00002000), CONST64(0x20202000,0x00002020), CONST64(0x20202020,0x00002020), + CONST64(0x20000000,0x00200000), CONST64(0x20000020,0x00200000), CONST64(0x20000000,0x00200020), CONST64(0x20000020,0x00200020), + CONST64(0x20002000,0x00200000), CONST64(0x20002020,0x00200000), CONST64(0x20002000,0x00200020), CONST64(0x20002020,0x00200020), + CONST64(0x20000000,0x00202000), CONST64(0x20000020,0x00202000), CONST64(0x20000000,0x00202020), CONST64(0x20000020,0x00202020), + CONST64(0x20002000,0x00202000), CONST64(0x20002020,0x00202000), CONST64(0x20002000,0x00202020), CONST64(0x20002020,0x00202020), + CONST64(0x20200000,0x00200000), CONST64(0x20200020,0x00200000), CONST64(0x20200000,0x00200020), CONST64(0x20200020,0x00200020), + CONST64(0x20202000,0x00200000), CONST64(0x20202020,0x00200000), CONST64(0x20202000,0x00200020), CONST64(0x20202020,0x00200020), + CONST64(0x20200000,0x00202000), CONST64(0x20200020,0x00202000), CONST64(0x20200000,0x00202020), CONST64(0x20200020,0x00202020), + CONST64(0x20202000,0x00202000), CONST64(0x20202020,0x00202000), CONST64(0x20202000,0x00202020), CONST64(0x20202020,0x00202020), + CONST64(0x00000000,0x20000000), CONST64(0x00000020,0x20000000), CONST64(0x00000000,0x20000020), CONST64(0x00000020,0x20000020), + CONST64(0x00002000,0x20000000), CONST64(0x00002020,0x20000000), CONST64(0x00002000,0x20000020), CONST64(0x00002020,0x20000020), + CONST64(0x00000000,0x20002000), CONST64(0x00000020,0x20002000), CONST64(0x00000000,0x20002020), CONST64(0x00000020,0x20002020), + CONST64(0x00002000,0x20002000), CONST64(0x00002020,0x20002000), CONST64(0x00002000,0x20002020), CONST64(0x00002020,0x20002020), + CONST64(0x00200000,0x20000000), CONST64(0x00200020,0x20000000), CONST64(0x00200000,0x20000020), CONST64(0x00200020,0x20000020), + CONST64(0x00202000,0x20000000), CONST64(0x00202020,0x20000000), CONST64(0x00202000,0x20000020), CONST64(0x00202020,0x20000020), + CONST64(0x00200000,0x20002000), CONST64(0x00200020,0x20002000), CONST64(0x00200000,0x20002020), CONST64(0x00200020,0x20002020), + CONST64(0x00202000,0x20002000), CONST64(0x00202020,0x20002000), CONST64(0x00202000,0x20002020), CONST64(0x00202020,0x20002020), + CONST64(0x00000000,0x20200000), CONST64(0x00000020,0x20200000), CONST64(0x00000000,0x20200020), CONST64(0x00000020,0x20200020), + CONST64(0x00002000,0x20200000), CONST64(0x00002020,0x20200000), CONST64(0x00002000,0x20200020), CONST64(0x00002020,0x20200020), + CONST64(0x00000000,0x20202000), CONST64(0x00000020,0x20202000), CONST64(0x00000000,0x20202020), CONST64(0x00000020,0x20202020), + CONST64(0x00002000,0x20202000), CONST64(0x00002020,0x20202000), CONST64(0x00002000,0x20202020), CONST64(0x00002020,0x20202020), + CONST64(0x00200000,0x20200000), CONST64(0x00200020,0x20200000), CONST64(0x00200000,0x20200020), CONST64(0x00200020,0x20200020), + CONST64(0x00202000,0x20200000), CONST64(0x00202020,0x20200000), CONST64(0x00202000,0x20200020), CONST64(0x00202020,0x20200020), + CONST64(0x00200000,0x20202000), CONST64(0x00200020,0x20202000), CONST64(0x00200000,0x20202020), CONST64(0x00200020,0x20202020), + CONST64(0x00202000,0x20202000), CONST64(0x00202020,0x20202000), CONST64(0x00202000,0x20202020), CONST64(0x00202020,0x20202020), + CONST64(0x20000000,0x20000000), CONST64(0x20000020,0x20000000), CONST64(0x20000000,0x20000020), CONST64(0x20000020,0x20000020), + CONST64(0x20002000,0x20000000), CONST64(0x20002020,0x20000000), CONST64(0x20002000,0x20000020), CONST64(0x20002020,0x20000020), + CONST64(0x20000000,0x20002000), CONST64(0x20000020,0x20002000), CONST64(0x20000000,0x20002020), CONST64(0x20000020,0x20002020), + CONST64(0x20002000,0x20002000), CONST64(0x20002020,0x20002000), CONST64(0x20002000,0x20002020), CONST64(0x20002020,0x20002020), + CONST64(0x20200000,0x20000000), CONST64(0x20200020,0x20000000), CONST64(0x20200000,0x20000020), CONST64(0x20200020,0x20000020), + CONST64(0x20202000,0x20000000), CONST64(0x20202020,0x20000000), CONST64(0x20202000,0x20000020), CONST64(0x20202020,0x20000020), + CONST64(0x20200000,0x20002000), CONST64(0x20200020,0x20002000), CONST64(0x20200000,0x20002020), CONST64(0x20200020,0x20002020), + CONST64(0x20202000,0x20002000), CONST64(0x20202020,0x20002000), CONST64(0x20202000,0x20002020), CONST64(0x20202020,0x20002020), + CONST64(0x20000000,0x20200000), CONST64(0x20000020,0x20200000), CONST64(0x20000000,0x20200020), CONST64(0x20000020,0x20200020), + CONST64(0x20002000,0x20200000), CONST64(0x20002020,0x20200000), CONST64(0x20002000,0x20200020), CONST64(0x20002020,0x20200020), + CONST64(0x20000000,0x20202000), CONST64(0x20000020,0x20202000), CONST64(0x20000000,0x20202020), CONST64(0x20000020,0x20202020), + CONST64(0x20002000,0x20202000), CONST64(0x20002020,0x20202000), CONST64(0x20002000,0x20202020), CONST64(0x20002020,0x20202020), + CONST64(0x20200000,0x20200000), CONST64(0x20200020,0x20200000), CONST64(0x20200000,0x20200020), CONST64(0x20200020,0x20200020), + CONST64(0x20202000,0x20200000), CONST64(0x20202020,0x20200000), CONST64(0x20202000,0x20200020), CONST64(0x20202020,0x20200020), + CONST64(0x20200000,0x20202000), CONST64(0x20200020,0x20202000), CONST64(0x20200000,0x20202020), CONST64(0x20200020,0x20202020), + CONST64(0x20202000,0x20202000), CONST64(0x20202020,0x20202000), CONST64(0x20202000,0x20202020), CONST64(0x20202020,0x20202020) + }}; + +static const ulong64 des_fp[8][256] = { + +{ CONST64(0x00000000,0x00000000), CONST64(0x00000080,0x00000000), CONST64(0x00000000,0x02000000), CONST64(0x00000080,0x02000000), + CONST64(0x00000000,0x00020000), CONST64(0x00000080,0x00020000), CONST64(0x00000000,0x02020000), CONST64(0x00000080,0x02020000), + CONST64(0x00000000,0x00000200), CONST64(0x00000080,0x00000200), CONST64(0x00000000,0x02000200), CONST64(0x00000080,0x02000200), + CONST64(0x00000000,0x00020200), CONST64(0x00000080,0x00020200), CONST64(0x00000000,0x02020200), CONST64(0x00000080,0x02020200), + CONST64(0x00000000,0x00000002), CONST64(0x00000080,0x00000002), CONST64(0x00000000,0x02000002), CONST64(0x00000080,0x02000002), + CONST64(0x00000000,0x00020002), CONST64(0x00000080,0x00020002), CONST64(0x00000000,0x02020002), CONST64(0x00000080,0x02020002), + CONST64(0x00000000,0x00000202), CONST64(0x00000080,0x00000202), CONST64(0x00000000,0x02000202), CONST64(0x00000080,0x02000202), + CONST64(0x00000000,0x00020202), CONST64(0x00000080,0x00020202), CONST64(0x00000000,0x02020202), CONST64(0x00000080,0x02020202), + CONST64(0x02000000,0x00000000), CONST64(0x02000080,0x00000000), CONST64(0x02000000,0x02000000), CONST64(0x02000080,0x02000000), + CONST64(0x02000000,0x00020000), CONST64(0x02000080,0x00020000), CONST64(0x02000000,0x02020000), CONST64(0x02000080,0x02020000), + CONST64(0x02000000,0x00000200), CONST64(0x02000080,0x00000200), CONST64(0x02000000,0x02000200), CONST64(0x02000080,0x02000200), + CONST64(0x02000000,0x00020200), CONST64(0x02000080,0x00020200), CONST64(0x02000000,0x02020200), CONST64(0x02000080,0x02020200), + CONST64(0x02000000,0x00000002), CONST64(0x02000080,0x00000002), CONST64(0x02000000,0x02000002), CONST64(0x02000080,0x02000002), + CONST64(0x02000000,0x00020002), CONST64(0x02000080,0x00020002), CONST64(0x02000000,0x02020002), CONST64(0x02000080,0x02020002), + CONST64(0x02000000,0x00000202), CONST64(0x02000080,0x00000202), CONST64(0x02000000,0x02000202), CONST64(0x02000080,0x02000202), + CONST64(0x02000000,0x00020202), CONST64(0x02000080,0x00020202), CONST64(0x02000000,0x02020202), CONST64(0x02000080,0x02020202), + CONST64(0x00020000,0x00000000), CONST64(0x00020080,0x00000000), CONST64(0x00020000,0x02000000), CONST64(0x00020080,0x02000000), + CONST64(0x00020000,0x00020000), CONST64(0x00020080,0x00020000), CONST64(0x00020000,0x02020000), CONST64(0x00020080,0x02020000), + CONST64(0x00020000,0x00000200), CONST64(0x00020080,0x00000200), CONST64(0x00020000,0x02000200), CONST64(0x00020080,0x02000200), + CONST64(0x00020000,0x00020200), CONST64(0x00020080,0x00020200), CONST64(0x00020000,0x02020200), CONST64(0x00020080,0x02020200), + CONST64(0x00020000,0x00000002), CONST64(0x00020080,0x00000002), CONST64(0x00020000,0x02000002), CONST64(0x00020080,0x02000002), + CONST64(0x00020000,0x00020002), CONST64(0x00020080,0x00020002), CONST64(0x00020000,0x02020002), CONST64(0x00020080,0x02020002), + CONST64(0x00020000,0x00000202), CONST64(0x00020080,0x00000202), CONST64(0x00020000,0x02000202), CONST64(0x00020080,0x02000202), + CONST64(0x00020000,0x00020202), CONST64(0x00020080,0x00020202), CONST64(0x00020000,0x02020202), CONST64(0x00020080,0x02020202), + CONST64(0x02020000,0x00000000), CONST64(0x02020080,0x00000000), CONST64(0x02020000,0x02000000), CONST64(0x02020080,0x02000000), + CONST64(0x02020000,0x00020000), CONST64(0x02020080,0x00020000), CONST64(0x02020000,0x02020000), CONST64(0x02020080,0x02020000), + CONST64(0x02020000,0x00000200), CONST64(0x02020080,0x00000200), CONST64(0x02020000,0x02000200), CONST64(0x02020080,0x02000200), + CONST64(0x02020000,0x00020200), CONST64(0x02020080,0x00020200), CONST64(0x02020000,0x02020200), CONST64(0x02020080,0x02020200), + CONST64(0x02020000,0x00000002), CONST64(0x02020080,0x00000002), CONST64(0x02020000,0x02000002), CONST64(0x02020080,0x02000002), + CONST64(0x02020000,0x00020002), CONST64(0x02020080,0x00020002), CONST64(0x02020000,0x02020002), CONST64(0x02020080,0x02020002), + CONST64(0x02020000,0x00000202), CONST64(0x02020080,0x00000202), CONST64(0x02020000,0x02000202), CONST64(0x02020080,0x02000202), + CONST64(0x02020000,0x00020202), CONST64(0x02020080,0x00020202), CONST64(0x02020000,0x02020202), CONST64(0x02020080,0x02020202), + CONST64(0x00000200,0x00000000), CONST64(0x00000280,0x00000000), CONST64(0x00000200,0x02000000), CONST64(0x00000280,0x02000000), + CONST64(0x00000200,0x00020000), CONST64(0x00000280,0x00020000), CONST64(0x00000200,0x02020000), CONST64(0x00000280,0x02020000), + CONST64(0x00000200,0x00000200), CONST64(0x00000280,0x00000200), CONST64(0x00000200,0x02000200), CONST64(0x00000280,0x02000200), + CONST64(0x00000200,0x00020200), CONST64(0x00000280,0x00020200), CONST64(0x00000200,0x02020200), CONST64(0x00000280,0x02020200), + CONST64(0x00000200,0x00000002), CONST64(0x00000280,0x00000002), CONST64(0x00000200,0x02000002), CONST64(0x00000280,0x02000002), + CONST64(0x00000200,0x00020002), CONST64(0x00000280,0x00020002), CONST64(0x00000200,0x02020002), CONST64(0x00000280,0x02020002), + CONST64(0x00000200,0x00000202), CONST64(0x00000280,0x00000202), CONST64(0x00000200,0x02000202), CONST64(0x00000280,0x02000202), + CONST64(0x00000200,0x00020202), CONST64(0x00000280,0x00020202), CONST64(0x00000200,0x02020202), CONST64(0x00000280,0x02020202), + CONST64(0x02000200,0x00000000), CONST64(0x02000280,0x00000000), CONST64(0x02000200,0x02000000), CONST64(0x02000280,0x02000000), + CONST64(0x02000200,0x00020000), CONST64(0x02000280,0x00020000), CONST64(0x02000200,0x02020000), CONST64(0x02000280,0x02020000), + CONST64(0x02000200,0x00000200), CONST64(0x02000280,0x00000200), CONST64(0x02000200,0x02000200), CONST64(0x02000280,0x02000200), + CONST64(0x02000200,0x00020200), CONST64(0x02000280,0x00020200), CONST64(0x02000200,0x02020200), CONST64(0x02000280,0x02020200), + CONST64(0x02000200,0x00000002), CONST64(0x02000280,0x00000002), CONST64(0x02000200,0x02000002), CONST64(0x02000280,0x02000002), + CONST64(0x02000200,0x00020002), CONST64(0x02000280,0x00020002), CONST64(0x02000200,0x02020002), CONST64(0x02000280,0x02020002), + CONST64(0x02000200,0x00000202), CONST64(0x02000280,0x00000202), CONST64(0x02000200,0x02000202), CONST64(0x02000280,0x02000202), + CONST64(0x02000200,0x00020202), CONST64(0x02000280,0x00020202), CONST64(0x02000200,0x02020202), CONST64(0x02000280,0x02020202), + CONST64(0x00020200,0x00000000), CONST64(0x00020280,0x00000000), CONST64(0x00020200,0x02000000), CONST64(0x00020280,0x02000000), + CONST64(0x00020200,0x00020000), CONST64(0x00020280,0x00020000), CONST64(0x00020200,0x02020000), CONST64(0x00020280,0x02020000), + CONST64(0x00020200,0x00000200), CONST64(0x00020280,0x00000200), CONST64(0x00020200,0x02000200), CONST64(0x00020280,0x02000200), + CONST64(0x00020200,0x00020200), CONST64(0x00020280,0x00020200), CONST64(0x00020200,0x02020200), CONST64(0x00020280,0x02020200), + CONST64(0x00020200,0x00000002), CONST64(0x00020280,0x00000002), CONST64(0x00020200,0x02000002), CONST64(0x00020280,0x02000002), + CONST64(0x00020200,0x00020002), CONST64(0x00020280,0x00020002), CONST64(0x00020200,0x02020002), CONST64(0x00020280,0x02020002), + CONST64(0x00020200,0x00000202), CONST64(0x00020280,0x00000202), CONST64(0x00020200,0x02000202), CONST64(0x00020280,0x02000202), + CONST64(0x00020200,0x00020202), CONST64(0x00020280,0x00020202), CONST64(0x00020200,0x02020202), CONST64(0x00020280,0x02020202), + CONST64(0x02020200,0x00000000), CONST64(0x02020280,0x00000000), CONST64(0x02020200,0x02000000), CONST64(0x02020280,0x02000000), + CONST64(0x02020200,0x00020000), CONST64(0x02020280,0x00020000), CONST64(0x02020200,0x02020000), CONST64(0x02020280,0x02020000), + CONST64(0x02020200,0x00000200), CONST64(0x02020280,0x00000200), CONST64(0x02020200,0x02000200), CONST64(0x02020280,0x02000200), + CONST64(0x02020200,0x00020200), CONST64(0x02020280,0x00020200), CONST64(0x02020200,0x02020200), CONST64(0x02020280,0x02020200), + CONST64(0x02020200,0x00000002), CONST64(0x02020280,0x00000002), CONST64(0x02020200,0x02000002), CONST64(0x02020280,0x02000002), + CONST64(0x02020200,0x00020002), CONST64(0x02020280,0x00020002), CONST64(0x02020200,0x02020002), CONST64(0x02020280,0x02020002), + CONST64(0x02020200,0x00000202), CONST64(0x02020280,0x00000202), CONST64(0x02020200,0x02000202), CONST64(0x02020280,0x02000202), + CONST64(0x02020200,0x00020202), CONST64(0x02020280,0x00020202), CONST64(0x02020200,0x02020202), CONST64(0x02020280,0x02020202) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000002,0x00000000), CONST64(0x00000000,0x08000000), CONST64(0x00000002,0x08000000), + CONST64(0x00000000,0x00080000), CONST64(0x00000002,0x00080000), CONST64(0x00000000,0x08080000), CONST64(0x00000002,0x08080000), + CONST64(0x00000000,0x00000800), CONST64(0x00000002,0x00000800), CONST64(0x00000000,0x08000800), CONST64(0x00000002,0x08000800), + CONST64(0x00000000,0x00080800), CONST64(0x00000002,0x00080800), CONST64(0x00000000,0x08080800), CONST64(0x00000002,0x08080800), + CONST64(0x00000000,0x00000008), CONST64(0x00000002,0x00000008), CONST64(0x00000000,0x08000008), CONST64(0x00000002,0x08000008), + CONST64(0x00000000,0x00080008), CONST64(0x00000002,0x00080008), CONST64(0x00000000,0x08080008), CONST64(0x00000002,0x08080008), + CONST64(0x00000000,0x00000808), CONST64(0x00000002,0x00000808), CONST64(0x00000000,0x08000808), CONST64(0x00000002,0x08000808), + CONST64(0x00000000,0x00080808), CONST64(0x00000002,0x00080808), CONST64(0x00000000,0x08080808), CONST64(0x00000002,0x08080808), + CONST64(0x08000000,0x00000000), CONST64(0x08000002,0x00000000), CONST64(0x08000000,0x08000000), CONST64(0x08000002,0x08000000), + CONST64(0x08000000,0x00080000), CONST64(0x08000002,0x00080000), CONST64(0x08000000,0x08080000), CONST64(0x08000002,0x08080000), + CONST64(0x08000000,0x00000800), CONST64(0x08000002,0x00000800), CONST64(0x08000000,0x08000800), CONST64(0x08000002,0x08000800), + CONST64(0x08000000,0x00080800), CONST64(0x08000002,0x00080800), CONST64(0x08000000,0x08080800), CONST64(0x08000002,0x08080800), + CONST64(0x08000000,0x00000008), CONST64(0x08000002,0x00000008), CONST64(0x08000000,0x08000008), CONST64(0x08000002,0x08000008), + CONST64(0x08000000,0x00080008), CONST64(0x08000002,0x00080008), CONST64(0x08000000,0x08080008), CONST64(0x08000002,0x08080008), + CONST64(0x08000000,0x00000808), CONST64(0x08000002,0x00000808), CONST64(0x08000000,0x08000808), CONST64(0x08000002,0x08000808), + CONST64(0x08000000,0x00080808), CONST64(0x08000002,0x00080808), CONST64(0x08000000,0x08080808), CONST64(0x08000002,0x08080808), + CONST64(0x00080000,0x00000000), CONST64(0x00080002,0x00000000), CONST64(0x00080000,0x08000000), CONST64(0x00080002,0x08000000), + CONST64(0x00080000,0x00080000), CONST64(0x00080002,0x00080000), CONST64(0x00080000,0x08080000), CONST64(0x00080002,0x08080000), + CONST64(0x00080000,0x00000800), CONST64(0x00080002,0x00000800), CONST64(0x00080000,0x08000800), CONST64(0x00080002,0x08000800), + CONST64(0x00080000,0x00080800), CONST64(0x00080002,0x00080800), CONST64(0x00080000,0x08080800), CONST64(0x00080002,0x08080800), + CONST64(0x00080000,0x00000008), CONST64(0x00080002,0x00000008), CONST64(0x00080000,0x08000008), CONST64(0x00080002,0x08000008), + CONST64(0x00080000,0x00080008), CONST64(0x00080002,0x00080008), CONST64(0x00080000,0x08080008), CONST64(0x00080002,0x08080008), + CONST64(0x00080000,0x00000808), CONST64(0x00080002,0x00000808), CONST64(0x00080000,0x08000808), CONST64(0x00080002,0x08000808), + CONST64(0x00080000,0x00080808), CONST64(0x00080002,0x00080808), CONST64(0x00080000,0x08080808), CONST64(0x00080002,0x08080808), + CONST64(0x08080000,0x00000000), CONST64(0x08080002,0x00000000), CONST64(0x08080000,0x08000000), CONST64(0x08080002,0x08000000), + CONST64(0x08080000,0x00080000), CONST64(0x08080002,0x00080000), CONST64(0x08080000,0x08080000), CONST64(0x08080002,0x08080000), + CONST64(0x08080000,0x00000800), CONST64(0x08080002,0x00000800), CONST64(0x08080000,0x08000800), CONST64(0x08080002,0x08000800), + CONST64(0x08080000,0x00080800), CONST64(0x08080002,0x00080800), CONST64(0x08080000,0x08080800), CONST64(0x08080002,0x08080800), + CONST64(0x08080000,0x00000008), CONST64(0x08080002,0x00000008), CONST64(0x08080000,0x08000008), CONST64(0x08080002,0x08000008), + CONST64(0x08080000,0x00080008), CONST64(0x08080002,0x00080008), CONST64(0x08080000,0x08080008), CONST64(0x08080002,0x08080008), + CONST64(0x08080000,0x00000808), CONST64(0x08080002,0x00000808), CONST64(0x08080000,0x08000808), CONST64(0x08080002,0x08000808), + CONST64(0x08080000,0x00080808), CONST64(0x08080002,0x00080808), CONST64(0x08080000,0x08080808), CONST64(0x08080002,0x08080808), + CONST64(0x00000800,0x00000000), CONST64(0x00000802,0x00000000), CONST64(0x00000800,0x08000000), CONST64(0x00000802,0x08000000), + CONST64(0x00000800,0x00080000), CONST64(0x00000802,0x00080000), CONST64(0x00000800,0x08080000), CONST64(0x00000802,0x08080000), + CONST64(0x00000800,0x00000800), CONST64(0x00000802,0x00000800), CONST64(0x00000800,0x08000800), CONST64(0x00000802,0x08000800), + CONST64(0x00000800,0x00080800), CONST64(0x00000802,0x00080800), CONST64(0x00000800,0x08080800), CONST64(0x00000802,0x08080800), + CONST64(0x00000800,0x00000008), CONST64(0x00000802,0x00000008), CONST64(0x00000800,0x08000008), CONST64(0x00000802,0x08000008), + CONST64(0x00000800,0x00080008), CONST64(0x00000802,0x00080008), CONST64(0x00000800,0x08080008), CONST64(0x00000802,0x08080008), + CONST64(0x00000800,0x00000808), CONST64(0x00000802,0x00000808), CONST64(0x00000800,0x08000808), CONST64(0x00000802,0x08000808), + CONST64(0x00000800,0x00080808), CONST64(0x00000802,0x00080808), CONST64(0x00000800,0x08080808), CONST64(0x00000802,0x08080808), + CONST64(0x08000800,0x00000000), CONST64(0x08000802,0x00000000), CONST64(0x08000800,0x08000000), CONST64(0x08000802,0x08000000), + CONST64(0x08000800,0x00080000), CONST64(0x08000802,0x00080000), CONST64(0x08000800,0x08080000), CONST64(0x08000802,0x08080000), + CONST64(0x08000800,0x00000800), CONST64(0x08000802,0x00000800), CONST64(0x08000800,0x08000800), CONST64(0x08000802,0x08000800), + CONST64(0x08000800,0x00080800), CONST64(0x08000802,0x00080800), CONST64(0x08000800,0x08080800), CONST64(0x08000802,0x08080800), + CONST64(0x08000800,0x00000008), CONST64(0x08000802,0x00000008), CONST64(0x08000800,0x08000008), CONST64(0x08000802,0x08000008), + CONST64(0x08000800,0x00080008), CONST64(0x08000802,0x00080008), CONST64(0x08000800,0x08080008), CONST64(0x08000802,0x08080008), + CONST64(0x08000800,0x00000808), CONST64(0x08000802,0x00000808), CONST64(0x08000800,0x08000808), CONST64(0x08000802,0x08000808), + CONST64(0x08000800,0x00080808), CONST64(0x08000802,0x00080808), CONST64(0x08000800,0x08080808), CONST64(0x08000802,0x08080808), + CONST64(0x00080800,0x00000000), CONST64(0x00080802,0x00000000), CONST64(0x00080800,0x08000000), CONST64(0x00080802,0x08000000), + CONST64(0x00080800,0x00080000), CONST64(0x00080802,0x00080000), CONST64(0x00080800,0x08080000), CONST64(0x00080802,0x08080000), + CONST64(0x00080800,0x00000800), CONST64(0x00080802,0x00000800), CONST64(0x00080800,0x08000800), CONST64(0x00080802,0x08000800), + CONST64(0x00080800,0x00080800), CONST64(0x00080802,0x00080800), CONST64(0x00080800,0x08080800), CONST64(0x00080802,0x08080800), + CONST64(0x00080800,0x00000008), CONST64(0x00080802,0x00000008), CONST64(0x00080800,0x08000008), CONST64(0x00080802,0x08000008), + CONST64(0x00080800,0x00080008), CONST64(0x00080802,0x00080008), CONST64(0x00080800,0x08080008), CONST64(0x00080802,0x08080008), + CONST64(0x00080800,0x00000808), CONST64(0x00080802,0x00000808), CONST64(0x00080800,0x08000808), CONST64(0x00080802,0x08000808), + CONST64(0x00080800,0x00080808), CONST64(0x00080802,0x00080808), CONST64(0x00080800,0x08080808), CONST64(0x00080802,0x08080808), + CONST64(0x08080800,0x00000000), CONST64(0x08080802,0x00000000), CONST64(0x08080800,0x08000000), CONST64(0x08080802,0x08000000), + CONST64(0x08080800,0x00080000), CONST64(0x08080802,0x00080000), CONST64(0x08080800,0x08080000), CONST64(0x08080802,0x08080000), + CONST64(0x08080800,0x00000800), CONST64(0x08080802,0x00000800), CONST64(0x08080800,0x08000800), CONST64(0x08080802,0x08000800), + CONST64(0x08080800,0x00080800), CONST64(0x08080802,0x00080800), CONST64(0x08080800,0x08080800), CONST64(0x08080802,0x08080800), + CONST64(0x08080800,0x00000008), CONST64(0x08080802,0x00000008), CONST64(0x08080800,0x08000008), CONST64(0x08080802,0x08000008), + CONST64(0x08080800,0x00080008), CONST64(0x08080802,0x00080008), CONST64(0x08080800,0x08080008), CONST64(0x08080802,0x08080008), + CONST64(0x08080800,0x00000808), CONST64(0x08080802,0x00000808), CONST64(0x08080800,0x08000808), CONST64(0x08080802,0x08000808), + CONST64(0x08080800,0x00080808), CONST64(0x08080802,0x00080808), CONST64(0x08080800,0x08080808), CONST64(0x08080802,0x08080808) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000008,0x00000000), CONST64(0x00000000,0x20000000), CONST64(0x00000008,0x20000000), + CONST64(0x00000000,0x00200000), CONST64(0x00000008,0x00200000), CONST64(0x00000000,0x20200000), CONST64(0x00000008,0x20200000), + CONST64(0x00000000,0x00002000), CONST64(0x00000008,0x00002000), CONST64(0x00000000,0x20002000), CONST64(0x00000008,0x20002000), + CONST64(0x00000000,0x00202000), CONST64(0x00000008,0x00202000), CONST64(0x00000000,0x20202000), CONST64(0x00000008,0x20202000), + CONST64(0x00000000,0x00000020), CONST64(0x00000008,0x00000020), CONST64(0x00000000,0x20000020), CONST64(0x00000008,0x20000020), + CONST64(0x00000000,0x00200020), CONST64(0x00000008,0x00200020), CONST64(0x00000000,0x20200020), CONST64(0x00000008,0x20200020), + CONST64(0x00000000,0x00002020), CONST64(0x00000008,0x00002020), CONST64(0x00000000,0x20002020), CONST64(0x00000008,0x20002020), + CONST64(0x00000000,0x00202020), CONST64(0x00000008,0x00202020), CONST64(0x00000000,0x20202020), CONST64(0x00000008,0x20202020), + CONST64(0x20000000,0x00000000), CONST64(0x20000008,0x00000000), CONST64(0x20000000,0x20000000), CONST64(0x20000008,0x20000000), + CONST64(0x20000000,0x00200000), CONST64(0x20000008,0x00200000), CONST64(0x20000000,0x20200000), CONST64(0x20000008,0x20200000), + CONST64(0x20000000,0x00002000), CONST64(0x20000008,0x00002000), CONST64(0x20000000,0x20002000), CONST64(0x20000008,0x20002000), + CONST64(0x20000000,0x00202000), CONST64(0x20000008,0x00202000), CONST64(0x20000000,0x20202000), CONST64(0x20000008,0x20202000), + CONST64(0x20000000,0x00000020), CONST64(0x20000008,0x00000020), CONST64(0x20000000,0x20000020), CONST64(0x20000008,0x20000020), + CONST64(0x20000000,0x00200020), CONST64(0x20000008,0x00200020), CONST64(0x20000000,0x20200020), CONST64(0x20000008,0x20200020), + CONST64(0x20000000,0x00002020), CONST64(0x20000008,0x00002020), CONST64(0x20000000,0x20002020), CONST64(0x20000008,0x20002020), + CONST64(0x20000000,0x00202020), CONST64(0x20000008,0x00202020), CONST64(0x20000000,0x20202020), CONST64(0x20000008,0x20202020), + CONST64(0x00200000,0x00000000), CONST64(0x00200008,0x00000000), CONST64(0x00200000,0x20000000), CONST64(0x00200008,0x20000000), + CONST64(0x00200000,0x00200000), CONST64(0x00200008,0x00200000), CONST64(0x00200000,0x20200000), CONST64(0x00200008,0x20200000), + CONST64(0x00200000,0x00002000), CONST64(0x00200008,0x00002000), CONST64(0x00200000,0x20002000), CONST64(0x00200008,0x20002000), + CONST64(0x00200000,0x00202000), CONST64(0x00200008,0x00202000), CONST64(0x00200000,0x20202000), CONST64(0x00200008,0x20202000), + CONST64(0x00200000,0x00000020), CONST64(0x00200008,0x00000020), CONST64(0x00200000,0x20000020), CONST64(0x00200008,0x20000020), + CONST64(0x00200000,0x00200020), CONST64(0x00200008,0x00200020), CONST64(0x00200000,0x20200020), CONST64(0x00200008,0x20200020), + CONST64(0x00200000,0x00002020), CONST64(0x00200008,0x00002020), CONST64(0x00200000,0x20002020), CONST64(0x00200008,0x20002020), + CONST64(0x00200000,0x00202020), CONST64(0x00200008,0x00202020), CONST64(0x00200000,0x20202020), CONST64(0x00200008,0x20202020), + CONST64(0x20200000,0x00000000), CONST64(0x20200008,0x00000000), CONST64(0x20200000,0x20000000), CONST64(0x20200008,0x20000000), + CONST64(0x20200000,0x00200000), CONST64(0x20200008,0x00200000), CONST64(0x20200000,0x20200000), CONST64(0x20200008,0x20200000), + CONST64(0x20200000,0x00002000), CONST64(0x20200008,0x00002000), CONST64(0x20200000,0x20002000), CONST64(0x20200008,0x20002000), + CONST64(0x20200000,0x00202000), CONST64(0x20200008,0x00202000), CONST64(0x20200000,0x20202000), CONST64(0x20200008,0x20202000), + CONST64(0x20200000,0x00000020), CONST64(0x20200008,0x00000020), CONST64(0x20200000,0x20000020), CONST64(0x20200008,0x20000020), + CONST64(0x20200000,0x00200020), CONST64(0x20200008,0x00200020), CONST64(0x20200000,0x20200020), CONST64(0x20200008,0x20200020), + CONST64(0x20200000,0x00002020), CONST64(0x20200008,0x00002020), CONST64(0x20200000,0x20002020), CONST64(0x20200008,0x20002020), + CONST64(0x20200000,0x00202020), CONST64(0x20200008,0x00202020), CONST64(0x20200000,0x20202020), CONST64(0x20200008,0x20202020), + CONST64(0x00002000,0x00000000), CONST64(0x00002008,0x00000000), CONST64(0x00002000,0x20000000), CONST64(0x00002008,0x20000000), + CONST64(0x00002000,0x00200000), CONST64(0x00002008,0x00200000), CONST64(0x00002000,0x20200000), CONST64(0x00002008,0x20200000), + CONST64(0x00002000,0x00002000), CONST64(0x00002008,0x00002000), CONST64(0x00002000,0x20002000), CONST64(0x00002008,0x20002000), + CONST64(0x00002000,0x00202000), CONST64(0x00002008,0x00202000), CONST64(0x00002000,0x20202000), CONST64(0x00002008,0x20202000), + CONST64(0x00002000,0x00000020), CONST64(0x00002008,0x00000020), CONST64(0x00002000,0x20000020), CONST64(0x00002008,0x20000020), + CONST64(0x00002000,0x00200020), CONST64(0x00002008,0x00200020), CONST64(0x00002000,0x20200020), CONST64(0x00002008,0x20200020), + CONST64(0x00002000,0x00002020), CONST64(0x00002008,0x00002020), CONST64(0x00002000,0x20002020), CONST64(0x00002008,0x20002020), + CONST64(0x00002000,0x00202020), CONST64(0x00002008,0x00202020), CONST64(0x00002000,0x20202020), CONST64(0x00002008,0x20202020), + CONST64(0x20002000,0x00000000), CONST64(0x20002008,0x00000000), CONST64(0x20002000,0x20000000), CONST64(0x20002008,0x20000000), + CONST64(0x20002000,0x00200000), CONST64(0x20002008,0x00200000), CONST64(0x20002000,0x20200000), CONST64(0x20002008,0x20200000), + CONST64(0x20002000,0x00002000), CONST64(0x20002008,0x00002000), CONST64(0x20002000,0x20002000), CONST64(0x20002008,0x20002000), + CONST64(0x20002000,0x00202000), CONST64(0x20002008,0x00202000), CONST64(0x20002000,0x20202000), CONST64(0x20002008,0x20202000), + CONST64(0x20002000,0x00000020), CONST64(0x20002008,0x00000020), CONST64(0x20002000,0x20000020), CONST64(0x20002008,0x20000020), + CONST64(0x20002000,0x00200020), CONST64(0x20002008,0x00200020), CONST64(0x20002000,0x20200020), CONST64(0x20002008,0x20200020), + CONST64(0x20002000,0x00002020), CONST64(0x20002008,0x00002020), CONST64(0x20002000,0x20002020), CONST64(0x20002008,0x20002020), + CONST64(0x20002000,0x00202020), CONST64(0x20002008,0x00202020), CONST64(0x20002000,0x20202020), CONST64(0x20002008,0x20202020), + CONST64(0x00202000,0x00000000), CONST64(0x00202008,0x00000000), CONST64(0x00202000,0x20000000), CONST64(0x00202008,0x20000000), + CONST64(0x00202000,0x00200000), CONST64(0x00202008,0x00200000), CONST64(0x00202000,0x20200000), CONST64(0x00202008,0x20200000), + CONST64(0x00202000,0x00002000), CONST64(0x00202008,0x00002000), CONST64(0x00202000,0x20002000), CONST64(0x00202008,0x20002000), + CONST64(0x00202000,0x00202000), CONST64(0x00202008,0x00202000), CONST64(0x00202000,0x20202000), CONST64(0x00202008,0x20202000), + CONST64(0x00202000,0x00000020), CONST64(0x00202008,0x00000020), CONST64(0x00202000,0x20000020), CONST64(0x00202008,0x20000020), + CONST64(0x00202000,0x00200020), CONST64(0x00202008,0x00200020), CONST64(0x00202000,0x20200020), CONST64(0x00202008,0x20200020), + CONST64(0x00202000,0x00002020), CONST64(0x00202008,0x00002020), CONST64(0x00202000,0x20002020), CONST64(0x00202008,0x20002020), + CONST64(0x00202000,0x00202020), CONST64(0x00202008,0x00202020), CONST64(0x00202000,0x20202020), CONST64(0x00202008,0x20202020), + CONST64(0x20202000,0x00000000), CONST64(0x20202008,0x00000000), CONST64(0x20202000,0x20000000), CONST64(0x20202008,0x20000000), + CONST64(0x20202000,0x00200000), CONST64(0x20202008,0x00200000), CONST64(0x20202000,0x20200000), CONST64(0x20202008,0x20200000), + CONST64(0x20202000,0x00002000), CONST64(0x20202008,0x00002000), CONST64(0x20202000,0x20002000), CONST64(0x20202008,0x20002000), + CONST64(0x20202000,0x00202000), CONST64(0x20202008,0x00202000), CONST64(0x20202000,0x20202000), CONST64(0x20202008,0x20202000), + CONST64(0x20202000,0x00000020), CONST64(0x20202008,0x00000020), CONST64(0x20202000,0x20000020), CONST64(0x20202008,0x20000020), + CONST64(0x20202000,0x00200020), CONST64(0x20202008,0x00200020), CONST64(0x20202000,0x20200020), CONST64(0x20202008,0x20200020), + CONST64(0x20202000,0x00002020), CONST64(0x20202008,0x00002020), CONST64(0x20202000,0x20002020), CONST64(0x20202008,0x20002020), + CONST64(0x20202000,0x00202020), CONST64(0x20202008,0x00202020), CONST64(0x20202000,0x20202020), CONST64(0x20202008,0x20202020) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000020,0x00000000), CONST64(0x00000000,0x80000000), CONST64(0x00000020,0x80000000), + CONST64(0x00000000,0x00800000), CONST64(0x00000020,0x00800000), CONST64(0x00000000,0x80800000), CONST64(0x00000020,0x80800000), + CONST64(0x00000000,0x00008000), CONST64(0x00000020,0x00008000), CONST64(0x00000000,0x80008000), CONST64(0x00000020,0x80008000), + CONST64(0x00000000,0x00808000), CONST64(0x00000020,0x00808000), CONST64(0x00000000,0x80808000), CONST64(0x00000020,0x80808000), + CONST64(0x00000000,0x00000080), CONST64(0x00000020,0x00000080), CONST64(0x00000000,0x80000080), CONST64(0x00000020,0x80000080), + CONST64(0x00000000,0x00800080), CONST64(0x00000020,0x00800080), CONST64(0x00000000,0x80800080), CONST64(0x00000020,0x80800080), + CONST64(0x00000000,0x00008080), CONST64(0x00000020,0x00008080), CONST64(0x00000000,0x80008080), CONST64(0x00000020,0x80008080), + CONST64(0x00000000,0x00808080), CONST64(0x00000020,0x00808080), CONST64(0x00000000,0x80808080), CONST64(0x00000020,0x80808080), + CONST64(0x80000000,0x00000000), CONST64(0x80000020,0x00000000), CONST64(0x80000000,0x80000000), CONST64(0x80000020,0x80000000), + CONST64(0x80000000,0x00800000), CONST64(0x80000020,0x00800000), CONST64(0x80000000,0x80800000), CONST64(0x80000020,0x80800000), + CONST64(0x80000000,0x00008000), CONST64(0x80000020,0x00008000), CONST64(0x80000000,0x80008000), CONST64(0x80000020,0x80008000), + CONST64(0x80000000,0x00808000), CONST64(0x80000020,0x00808000), CONST64(0x80000000,0x80808000), CONST64(0x80000020,0x80808000), + CONST64(0x80000000,0x00000080), CONST64(0x80000020,0x00000080), CONST64(0x80000000,0x80000080), CONST64(0x80000020,0x80000080), + CONST64(0x80000000,0x00800080), CONST64(0x80000020,0x00800080), CONST64(0x80000000,0x80800080), CONST64(0x80000020,0x80800080), + CONST64(0x80000000,0x00008080), CONST64(0x80000020,0x00008080), CONST64(0x80000000,0x80008080), CONST64(0x80000020,0x80008080), + CONST64(0x80000000,0x00808080), CONST64(0x80000020,0x00808080), CONST64(0x80000000,0x80808080), CONST64(0x80000020,0x80808080), + CONST64(0x00800000,0x00000000), CONST64(0x00800020,0x00000000), CONST64(0x00800000,0x80000000), CONST64(0x00800020,0x80000000), + CONST64(0x00800000,0x00800000), CONST64(0x00800020,0x00800000), CONST64(0x00800000,0x80800000), CONST64(0x00800020,0x80800000), + CONST64(0x00800000,0x00008000), CONST64(0x00800020,0x00008000), CONST64(0x00800000,0x80008000), CONST64(0x00800020,0x80008000), + CONST64(0x00800000,0x00808000), CONST64(0x00800020,0x00808000), CONST64(0x00800000,0x80808000), CONST64(0x00800020,0x80808000), + CONST64(0x00800000,0x00000080), CONST64(0x00800020,0x00000080), CONST64(0x00800000,0x80000080), CONST64(0x00800020,0x80000080), + CONST64(0x00800000,0x00800080), CONST64(0x00800020,0x00800080), CONST64(0x00800000,0x80800080), CONST64(0x00800020,0x80800080), + CONST64(0x00800000,0x00008080), CONST64(0x00800020,0x00008080), CONST64(0x00800000,0x80008080), CONST64(0x00800020,0x80008080), + CONST64(0x00800000,0x00808080), CONST64(0x00800020,0x00808080), CONST64(0x00800000,0x80808080), CONST64(0x00800020,0x80808080), + CONST64(0x80800000,0x00000000), CONST64(0x80800020,0x00000000), CONST64(0x80800000,0x80000000), CONST64(0x80800020,0x80000000), + CONST64(0x80800000,0x00800000), CONST64(0x80800020,0x00800000), CONST64(0x80800000,0x80800000), CONST64(0x80800020,0x80800000), + CONST64(0x80800000,0x00008000), CONST64(0x80800020,0x00008000), CONST64(0x80800000,0x80008000), CONST64(0x80800020,0x80008000), + CONST64(0x80800000,0x00808000), CONST64(0x80800020,0x00808000), CONST64(0x80800000,0x80808000), CONST64(0x80800020,0x80808000), + CONST64(0x80800000,0x00000080), CONST64(0x80800020,0x00000080), CONST64(0x80800000,0x80000080), CONST64(0x80800020,0x80000080), + CONST64(0x80800000,0x00800080), CONST64(0x80800020,0x00800080), CONST64(0x80800000,0x80800080), CONST64(0x80800020,0x80800080), + CONST64(0x80800000,0x00008080), CONST64(0x80800020,0x00008080), CONST64(0x80800000,0x80008080), CONST64(0x80800020,0x80008080), + CONST64(0x80800000,0x00808080), CONST64(0x80800020,0x00808080), CONST64(0x80800000,0x80808080), CONST64(0x80800020,0x80808080), + CONST64(0x00008000,0x00000000), CONST64(0x00008020,0x00000000), CONST64(0x00008000,0x80000000), CONST64(0x00008020,0x80000000), + CONST64(0x00008000,0x00800000), CONST64(0x00008020,0x00800000), CONST64(0x00008000,0x80800000), CONST64(0x00008020,0x80800000), + CONST64(0x00008000,0x00008000), CONST64(0x00008020,0x00008000), CONST64(0x00008000,0x80008000), CONST64(0x00008020,0x80008000), + CONST64(0x00008000,0x00808000), CONST64(0x00008020,0x00808000), CONST64(0x00008000,0x80808000), CONST64(0x00008020,0x80808000), + CONST64(0x00008000,0x00000080), CONST64(0x00008020,0x00000080), CONST64(0x00008000,0x80000080), CONST64(0x00008020,0x80000080), + CONST64(0x00008000,0x00800080), CONST64(0x00008020,0x00800080), CONST64(0x00008000,0x80800080), CONST64(0x00008020,0x80800080), + CONST64(0x00008000,0x00008080), CONST64(0x00008020,0x00008080), CONST64(0x00008000,0x80008080), CONST64(0x00008020,0x80008080), + CONST64(0x00008000,0x00808080), CONST64(0x00008020,0x00808080), CONST64(0x00008000,0x80808080), CONST64(0x00008020,0x80808080), + CONST64(0x80008000,0x00000000), CONST64(0x80008020,0x00000000), CONST64(0x80008000,0x80000000), CONST64(0x80008020,0x80000000), + CONST64(0x80008000,0x00800000), CONST64(0x80008020,0x00800000), CONST64(0x80008000,0x80800000), CONST64(0x80008020,0x80800000), + CONST64(0x80008000,0x00008000), CONST64(0x80008020,0x00008000), CONST64(0x80008000,0x80008000), CONST64(0x80008020,0x80008000), + CONST64(0x80008000,0x00808000), CONST64(0x80008020,0x00808000), CONST64(0x80008000,0x80808000), CONST64(0x80008020,0x80808000), + CONST64(0x80008000,0x00000080), CONST64(0x80008020,0x00000080), CONST64(0x80008000,0x80000080), CONST64(0x80008020,0x80000080), + CONST64(0x80008000,0x00800080), CONST64(0x80008020,0x00800080), CONST64(0x80008000,0x80800080), CONST64(0x80008020,0x80800080), + CONST64(0x80008000,0x00008080), CONST64(0x80008020,0x00008080), CONST64(0x80008000,0x80008080), CONST64(0x80008020,0x80008080), + CONST64(0x80008000,0x00808080), CONST64(0x80008020,0x00808080), CONST64(0x80008000,0x80808080), CONST64(0x80008020,0x80808080), + CONST64(0x00808000,0x00000000), CONST64(0x00808020,0x00000000), CONST64(0x00808000,0x80000000), CONST64(0x00808020,0x80000000), + CONST64(0x00808000,0x00800000), CONST64(0x00808020,0x00800000), CONST64(0x00808000,0x80800000), CONST64(0x00808020,0x80800000), + CONST64(0x00808000,0x00008000), CONST64(0x00808020,0x00008000), CONST64(0x00808000,0x80008000), CONST64(0x00808020,0x80008000), + CONST64(0x00808000,0x00808000), CONST64(0x00808020,0x00808000), CONST64(0x00808000,0x80808000), CONST64(0x00808020,0x80808000), + CONST64(0x00808000,0x00000080), CONST64(0x00808020,0x00000080), CONST64(0x00808000,0x80000080), CONST64(0x00808020,0x80000080), + CONST64(0x00808000,0x00800080), CONST64(0x00808020,0x00800080), CONST64(0x00808000,0x80800080), CONST64(0x00808020,0x80800080), + CONST64(0x00808000,0x00008080), CONST64(0x00808020,0x00008080), CONST64(0x00808000,0x80008080), CONST64(0x00808020,0x80008080), + CONST64(0x00808000,0x00808080), CONST64(0x00808020,0x00808080), CONST64(0x00808000,0x80808080), CONST64(0x00808020,0x80808080), + CONST64(0x80808000,0x00000000), CONST64(0x80808020,0x00000000), CONST64(0x80808000,0x80000000), CONST64(0x80808020,0x80000000), + CONST64(0x80808000,0x00800000), CONST64(0x80808020,0x00800000), CONST64(0x80808000,0x80800000), CONST64(0x80808020,0x80800000), + CONST64(0x80808000,0x00008000), CONST64(0x80808020,0x00008000), CONST64(0x80808000,0x80008000), CONST64(0x80808020,0x80008000), + CONST64(0x80808000,0x00808000), CONST64(0x80808020,0x00808000), CONST64(0x80808000,0x80808000), CONST64(0x80808020,0x80808000), + CONST64(0x80808000,0x00000080), CONST64(0x80808020,0x00000080), CONST64(0x80808000,0x80000080), CONST64(0x80808020,0x80000080), + CONST64(0x80808000,0x00800080), CONST64(0x80808020,0x00800080), CONST64(0x80808000,0x80800080), CONST64(0x80808020,0x80800080), + CONST64(0x80808000,0x00008080), CONST64(0x80808020,0x00008080), CONST64(0x80808000,0x80008080), CONST64(0x80808020,0x80008080), + CONST64(0x80808000,0x00808080), CONST64(0x80808020,0x00808080), CONST64(0x80808000,0x80808080), CONST64(0x80808020,0x80808080) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000040,0x00000000), CONST64(0x00000000,0x01000000), CONST64(0x00000040,0x01000000), + CONST64(0x00000000,0x00010000), CONST64(0x00000040,0x00010000), CONST64(0x00000000,0x01010000), CONST64(0x00000040,0x01010000), + CONST64(0x00000000,0x00000100), CONST64(0x00000040,0x00000100), CONST64(0x00000000,0x01000100), CONST64(0x00000040,0x01000100), + CONST64(0x00000000,0x00010100), CONST64(0x00000040,0x00010100), CONST64(0x00000000,0x01010100), CONST64(0x00000040,0x01010100), + CONST64(0x00000000,0x00000001), CONST64(0x00000040,0x00000001), CONST64(0x00000000,0x01000001), CONST64(0x00000040,0x01000001), + CONST64(0x00000000,0x00010001), CONST64(0x00000040,0x00010001), CONST64(0x00000000,0x01010001), CONST64(0x00000040,0x01010001), + CONST64(0x00000000,0x00000101), CONST64(0x00000040,0x00000101), CONST64(0x00000000,0x01000101), CONST64(0x00000040,0x01000101), + CONST64(0x00000000,0x00010101), CONST64(0x00000040,0x00010101), CONST64(0x00000000,0x01010101), CONST64(0x00000040,0x01010101), + CONST64(0x01000000,0x00000000), CONST64(0x01000040,0x00000000), CONST64(0x01000000,0x01000000), CONST64(0x01000040,0x01000000), + CONST64(0x01000000,0x00010000), CONST64(0x01000040,0x00010000), CONST64(0x01000000,0x01010000), CONST64(0x01000040,0x01010000), + CONST64(0x01000000,0x00000100), CONST64(0x01000040,0x00000100), CONST64(0x01000000,0x01000100), CONST64(0x01000040,0x01000100), + CONST64(0x01000000,0x00010100), CONST64(0x01000040,0x00010100), CONST64(0x01000000,0x01010100), CONST64(0x01000040,0x01010100), + CONST64(0x01000000,0x00000001), CONST64(0x01000040,0x00000001), CONST64(0x01000000,0x01000001), CONST64(0x01000040,0x01000001), + CONST64(0x01000000,0x00010001), CONST64(0x01000040,0x00010001), CONST64(0x01000000,0x01010001), CONST64(0x01000040,0x01010001), + CONST64(0x01000000,0x00000101), CONST64(0x01000040,0x00000101), CONST64(0x01000000,0x01000101), CONST64(0x01000040,0x01000101), + CONST64(0x01000000,0x00010101), CONST64(0x01000040,0x00010101), CONST64(0x01000000,0x01010101), CONST64(0x01000040,0x01010101), + CONST64(0x00010000,0x00000000), CONST64(0x00010040,0x00000000), CONST64(0x00010000,0x01000000), CONST64(0x00010040,0x01000000), + CONST64(0x00010000,0x00010000), CONST64(0x00010040,0x00010000), CONST64(0x00010000,0x01010000), CONST64(0x00010040,0x01010000), + CONST64(0x00010000,0x00000100), CONST64(0x00010040,0x00000100), CONST64(0x00010000,0x01000100), CONST64(0x00010040,0x01000100), + CONST64(0x00010000,0x00010100), CONST64(0x00010040,0x00010100), CONST64(0x00010000,0x01010100), CONST64(0x00010040,0x01010100), + CONST64(0x00010000,0x00000001), CONST64(0x00010040,0x00000001), CONST64(0x00010000,0x01000001), CONST64(0x00010040,0x01000001), + CONST64(0x00010000,0x00010001), CONST64(0x00010040,0x00010001), CONST64(0x00010000,0x01010001), CONST64(0x00010040,0x01010001), + CONST64(0x00010000,0x00000101), CONST64(0x00010040,0x00000101), CONST64(0x00010000,0x01000101), CONST64(0x00010040,0x01000101), + CONST64(0x00010000,0x00010101), CONST64(0x00010040,0x00010101), CONST64(0x00010000,0x01010101), CONST64(0x00010040,0x01010101), + CONST64(0x01010000,0x00000000), CONST64(0x01010040,0x00000000), CONST64(0x01010000,0x01000000), CONST64(0x01010040,0x01000000), + CONST64(0x01010000,0x00010000), CONST64(0x01010040,0x00010000), CONST64(0x01010000,0x01010000), CONST64(0x01010040,0x01010000), + CONST64(0x01010000,0x00000100), CONST64(0x01010040,0x00000100), CONST64(0x01010000,0x01000100), CONST64(0x01010040,0x01000100), + CONST64(0x01010000,0x00010100), CONST64(0x01010040,0x00010100), CONST64(0x01010000,0x01010100), CONST64(0x01010040,0x01010100), + CONST64(0x01010000,0x00000001), CONST64(0x01010040,0x00000001), CONST64(0x01010000,0x01000001), CONST64(0x01010040,0x01000001), + CONST64(0x01010000,0x00010001), CONST64(0x01010040,0x00010001), CONST64(0x01010000,0x01010001), CONST64(0x01010040,0x01010001), + CONST64(0x01010000,0x00000101), CONST64(0x01010040,0x00000101), CONST64(0x01010000,0x01000101), CONST64(0x01010040,0x01000101), + CONST64(0x01010000,0x00010101), CONST64(0x01010040,0x00010101), CONST64(0x01010000,0x01010101), CONST64(0x01010040,0x01010101), + CONST64(0x00000100,0x00000000), CONST64(0x00000140,0x00000000), CONST64(0x00000100,0x01000000), CONST64(0x00000140,0x01000000), + CONST64(0x00000100,0x00010000), CONST64(0x00000140,0x00010000), CONST64(0x00000100,0x01010000), CONST64(0x00000140,0x01010000), + CONST64(0x00000100,0x00000100), CONST64(0x00000140,0x00000100), CONST64(0x00000100,0x01000100), CONST64(0x00000140,0x01000100), + CONST64(0x00000100,0x00010100), CONST64(0x00000140,0x00010100), CONST64(0x00000100,0x01010100), CONST64(0x00000140,0x01010100), + CONST64(0x00000100,0x00000001), CONST64(0x00000140,0x00000001), CONST64(0x00000100,0x01000001), CONST64(0x00000140,0x01000001), + CONST64(0x00000100,0x00010001), CONST64(0x00000140,0x00010001), CONST64(0x00000100,0x01010001), CONST64(0x00000140,0x01010001), + CONST64(0x00000100,0x00000101), CONST64(0x00000140,0x00000101), CONST64(0x00000100,0x01000101), CONST64(0x00000140,0x01000101), + CONST64(0x00000100,0x00010101), CONST64(0x00000140,0x00010101), CONST64(0x00000100,0x01010101), CONST64(0x00000140,0x01010101), + CONST64(0x01000100,0x00000000), CONST64(0x01000140,0x00000000), CONST64(0x01000100,0x01000000), CONST64(0x01000140,0x01000000), + CONST64(0x01000100,0x00010000), CONST64(0x01000140,0x00010000), CONST64(0x01000100,0x01010000), CONST64(0x01000140,0x01010000), + CONST64(0x01000100,0x00000100), CONST64(0x01000140,0x00000100), CONST64(0x01000100,0x01000100), CONST64(0x01000140,0x01000100), + CONST64(0x01000100,0x00010100), CONST64(0x01000140,0x00010100), CONST64(0x01000100,0x01010100), CONST64(0x01000140,0x01010100), + CONST64(0x01000100,0x00000001), CONST64(0x01000140,0x00000001), CONST64(0x01000100,0x01000001), CONST64(0x01000140,0x01000001), + CONST64(0x01000100,0x00010001), CONST64(0x01000140,0x00010001), CONST64(0x01000100,0x01010001), CONST64(0x01000140,0x01010001), + CONST64(0x01000100,0x00000101), CONST64(0x01000140,0x00000101), CONST64(0x01000100,0x01000101), CONST64(0x01000140,0x01000101), + CONST64(0x01000100,0x00010101), CONST64(0x01000140,0x00010101), CONST64(0x01000100,0x01010101), CONST64(0x01000140,0x01010101), + CONST64(0x00010100,0x00000000), CONST64(0x00010140,0x00000000), CONST64(0x00010100,0x01000000), CONST64(0x00010140,0x01000000), + CONST64(0x00010100,0x00010000), CONST64(0x00010140,0x00010000), CONST64(0x00010100,0x01010000), CONST64(0x00010140,0x01010000), + CONST64(0x00010100,0x00000100), CONST64(0x00010140,0x00000100), CONST64(0x00010100,0x01000100), CONST64(0x00010140,0x01000100), + CONST64(0x00010100,0x00010100), CONST64(0x00010140,0x00010100), CONST64(0x00010100,0x01010100), CONST64(0x00010140,0x01010100), + CONST64(0x00010100,0x00000001), CONST64(0x00010140,0x00000001), CONST64(0x00010100,0x01000001), CONST64(0x00010140,0x01000001), + CONST64(0x00010100,0x00010001), CONST64(0x00010140,0x00010001), CONST64(0x00010100,0x01010001), CONST64(0x00010140,0x01010001), + CONST64(0x00010100,0x00000101), CONST64(0x00010140,0x00000101), CONST64(0x00010100,0x01000101), CONST64(0x00010140,0x01000101), + CONST64(0x00010100,0x00010101), CONST64(0x00010140,0x00010101), CONST64(0x00010100,0x01010101), CONST64(0x00010140,0x01010101), + CONST64(0x01010100,0x00000000), CONST64(0x01010140,0x00000000), CONST64(0x01010100,0x01000000), CONST64(0x01010140,0x01000000), + CONST64(0x01010100,0x00010000), CONST64(0x01010140,0x00010000), CONST64(0x01010100,0x01010000), CONST64(0x01010140,0x01010000), + CONST64(0x01010100,0x00000100), CONST64(0x01010140,0x00000100), CONST64(0x01010100,0x01000100), CONST64(0x01010140,0x01000100), + CONST64(0x01010100,0x00010100), CONST64(0x01010140,0x00010100), CONST64(0x01010100,0x01010100), CONST64(0x01010140,0x01010100), + CONST64(0x01010100,0x00000001), CONST64(0x01010140,0x00000001), CONST64(0x01010100,0x01000001), CONST64(0x01010140,0x01000001), + CONST64(0x01010100,0x00010001), CONST64(0x01010140,0x00010001), CONST64(0x01010100,0x01010001), CONST64(0x01010140,0x01010001), + CONST64(0x01010100,0x00000101), CONST64(0x01010140,0x00000101), CONST64(0x01010100,0x01000101), CONST64(0x01010140,0x01000101), + CONST64(0x01010100,0x00010101), CONST64(0x01010140,0x00010101), CONST64(0x01010100,0x01010101), CONST64(0x01010140,0x01010101) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000001,0x00000000), CONST64(0x00000000,0x04000000), CONST64(0x00000001,0x04000000), + CONST64(0x00000000,0x00040000), CONST64(0x00000001,0x00040000), CONST64(0x00000000,0x04040000), CONST64(0x00000001,0x04040000), + CONST64(0x00000000,0x00000400), CONST64(0x00000001,0x00000400), CONST64(0x00000000,0x04000400), CONST64(0x00000001,0x04000400), + CONST64(0x00000000,0x00040400), CONST64(0x00000001,0x00040400), CONST64(0x00000000,0x04040400), CONST64(0x00000001,0x04040400), + CONST64(0x00000000,0x00000004), CONST64(0x00000001,0x00000004), CONST64(0x00000000,0x04000004), CONST64(0x00000001,0x04000004), + CONST64(0x00000000,0x00040004), CONST64(0x00000001,0x00040004), CONST64(0x00000000,0x04040004), CONST64(0x00000001,0x04040004), + CONST64(0x00000000,0x00000404), CONST64(0x00000001,0x00000404), CONST64(0x00000000,0x04000404), CONST64(0x00000001,0x04000404), + CONST64(0x00000000,0x00040404), CONST64(0x00000001,0x00040404), CONST64(0x00000000,0x04040404), CONST64(0x00000001,0x04040404), + CONST64(0x04000000,0x00000000), CONST64(0x04000001,0x00000000), CONST64(0x04000000,0x04000000), CONST64(0x04000001,0x04000000), + CONST64(0x04000000,0x00040000), CONST64(0x04000001,0x00040000), CONST64(0x04000000,0x04040000), CONST64(0x04000001,0x04040000), + CONST64(0x04000000,0x00000400), CONST64(0x04000001,0x00000400), CONST64(0x04000000,0x04000400), CONST64(0x04000001,0x04000400), + CONST64(0x04000000,0x00040400), CONST64(0x04000001,0x00040400), CONST64(0x04000000,0x04040400), CONST64(0x04000001,0x04040400), + CONST64(0x04000000,0x00000004), CONST64(0x04000001,0x00000004), CONST64(0x04000000,0x04000004), CONST64(0x04000001,0x04000004), + CONST64(0x04000000,0x00040004), CONST64(0x04000001,0x00040004), CONST64(0x04000000,0x04040004), CONST64(0x04000001,0x04040004), + CONST64(0x04000000,0x00000404), CONST64(0x04000001,0x00000404), CONST64(0x04000000,0x04000404), CONST64(0x04000001,0x04000404), + CONST64(0x04000000,0x00040404), CONST64(0x04000001,0x00040404), CONST64(0x04000000,0x04040404), CONST64(0x04000001,0x04040404), + CONST64(0x00040000,0x00000000), CONST64(0x00040001,0x00000000), CONST64(0x00040000,0x04000000), CONST64(0x00040001,0x04000000), + CONST64(0x00040000,0x00040000), CONST64(0x00040001,0x00040000), CONST64(0x00040000,0x04040000), CONST64(0x00040001,0x04040000), + CONST64(0x00040000,0x00000400), CONST64(0x00040001,0x00000400), CONST64(0x00040000,0x04000400), CONST64(0x00040001,0x04000400), + CONST64(0x00040000,0x00040400), CONST64(0x00040001,0x00040400), CONST64(0x00040000,0x04040400), CONST64(0x00040001,0x04040400), + CONST64(0x00040000,0x00000004), CONST64(0x00040001,0x00000004), CONST64(0x00040000,0x04000004), CONST64(0x00040001,0x04000004), + CONST64(0x00040000,0x00040004), CONST64(0x00040001,0x00040004), CONST64(0x00040000,0x04040004), CONST64(0x00040001,0x04040004), + CONST64(0x00040000,0x00000404), CONST64(0x00040001,0x00000404), CONST64(0x00040000,0x04000404), CONST64(0x00040001,0x04000404), + CONST64(0x00040000,0x00040404), CONST64(0x00040001,0x00040404), CONST64(0x00040000,0x04040404), CONST64(0x00040001,0x04040404), + CONST64(0x04040000,0x00000000), CONST64(0x04040001,0x00000000), CONST64(0x04040000,0x04000000), CONST64(0x04040001,0x04000000), + CONST64(0x04040000,0x00040000), CONST64(0x04040001,0x00040000), CONST64(0x04040000,0x04040000), CONST64(0x04040001,0x04040000), + CONST64(0x04040000,0x00000400), CONST64(0x04040001,0x00000400), CONST64(0x04040000,0x04000400), CONST64(0x04040001,0x04000400), + CONST64(0x04040000,0x00040400), CONST64(0x04040001,0x00040400), CONST64(0x04040000,0x04040400), CONST64(0x04040001,0x04040400), + CONST64(0x04040000,0x00000004), CONST64(0x04040001,0x00000004), CONST64(0x04040000,0x04000004), CONST64(0x04040001,0x04000004), + CONST64(0x04040000,0x00040004), CONST64(0x04040001,0x00040004), CONST64(0x04040000,0x04040004), CONST64(0x04040001,0x04040004), + CONST64(0x04040000,0x00000404), CONST64(0x04040001,0x00000404), CONST64(0x04040000,0x04000404), CONST64(0x04040001,0x04000404), + CONST64(0x04040000,0x00040404), CONST64(0x04040001,0x00040404), CONST64(0x04040000,0x04040404), CONST64(0x04040001,0x04040404), + CONST64(0x00000400,0x00000000), CONST64(0x00000401,0x00000000), CONST64(0x00000400,0x04000000), CONST64(0x00000401,0x04000000), + CONST64(0x00000400,0x00040000), CONST64(0x00000401,0x00040000), CONST64(0x00000400,0x04040000), CONST64(0x00000401,0x04040000), + CONST64(0x00000400,0x00000400), CONST64(0x00000401,0x00000400), CONST64(0x00000400,0x04000400), CONST64(0x00000401,0x04000400), + CONST64(0x00000400,0x00040400), CONST64(0x00000401,0x00040400), CONST64(0x00000400,0x04040400), CONST64(0x00000401,0x04040400), + CONST64(0x00000400,0x00000004), CONST64(0x00000401,0x00000004), CONST64(0x00000400,0x04000004), CONST64(0x00000401,0x04000004), + CONST64(0x00000400,0x00040004), CONST64(0x00000401,0x00040004), CONST64(0x00000400,0x04040004), CONST64(0x00000401,0x04040004), + CONST64(0x00000400,0x00000404), CONST64(0x00000401,0x00000404), CONST64(0x00000400,0x04000404), CONST64(0x00000401,0x04000404), + CONST64(0x00000400,0x00040404), CONST64(0x00000401,0x00040404), CONST64(0x00000400,0x04040404), CONST64(0x00000401,0x04040404), + CONST64(0x04000400,0x00000000), CONST64(0x04000401,0x00000000), CONST64(0x04000400,0x04000000), CONST64(0x04000401,0x04000000), + CONST64(0x04000400,0x00040000), CONST64(0x04000401,0x00040000), CONST64(0x04000400,0x04040000), CONST64(0x04000401,0x04040000), + CONST64(0x04000400,0x00000400), CONST64(0x04000401,0x00000400), CONST64(0x04000400,0x04000400), CONST64(0x04000401,0x04000400), + CONST64(0x04000400,0x00040400), CONST64(0x04000401,0x00040400), CONST64(0x04000400,0x04040400), CONST64(0x04000401,0x04040400), + CONST64(0x04000400,0x00000004), CONST64(0x04000401,0x00000004), CONST64(0x04000400,0x04000004), CONST64(0x04000401,0x04000004), + CONST64(0x04000400,0x00040004), CONST64(0x04000401,0x00040004), CONST64(0x04000400,0x04040004), CONST64(0x04000401,0x04040004), + CONST64(0x04000400,0x00000404), CONST64(0x04000401,0x00000404), CONST64(0x04000400,0x04000404), CONST64(0x04000401,0x04000404), + CONST64(0x04000400,0x00040404), CONST64(0x04000401,0x00040404), CONST64(0x04000400,0x04040404), CONST64(0x04000401,0x04040404), + CONST64(0x00040400,0x00000000), CONST64(0x00040401,0x00000000), CONST64(0x00040400,0x04000000), CONST64(0x00040401,0x04000000), + CONST64(0x00040400,0x00040000), CONST64(0x00040401,0x00040000), CONST64(0x00040400,0x04040000), CONST64(0x00040401,0x04040000), + CONST64(0x00040400,0x00000400), CONST64(0x00040401,0x00000400), CONST64(0x00040400,0x04000400), CONST64(0x00040401,0x04000400), + CONST64(0x00040400,0x00040400), CONST64(0x00040401,0x00040400), CONST64(0x00040400,0x04040400), CONST64(0x00040401,0x04040400), + CONST64(0x00040400,0x00000004), CONST64(0x00040401,0x00000004), CONST64(0x00040400,0x04000004), CONST64(0x00040401,0x04000004), + CONST64(0x00040400,0x00040004), CONST64(0x00040401,0x00040004), CONST64(0x00040400,0x04040004), CONST64(0x00040401,0x04040004), + CONST64(0x00040400,0x00000404), CONST64(0x00040401,0x00000404), CONST64(0x00040400,0x04000404), CONST64(0x00040401,0x04000404), + CONST64(0x00040400,0x00040404), CONST64(0x00040401,0x00040404), CONST64(0x00040400,0x04040404), CONST64(0x00040401,0x04040404), + CONST64(0x04040400,0x00000000), CONST64(0x04040401,0x00000000), CONST64(0x04040400,0x04000000), CONST64(0x04040401,0x04000000), + CONST64(0x04040400,0x00040000), CONST64(0x04040401,0x00040000), CONST64(0x04040400,0x04040000), CONST64(0x04040401,0x04040000), + CONST64(0x04040400,0x00000400), CONST64(0x04040401,0x00000400), CONST64(0x04040400,0x04000400), CONST64(0x04040401,0x04000400), + CONST64(0x04040400,0x00040400), CONST64(0x04040401,0x00040400), CONST64(0x04040400,0x04040400), CONST64(0x04040401,0x04040400), + CONST64(0x04040400,0x00000004), CONST64(0x04040401,0x00000004), CONST64(0x04040400,0x04000004), CONST64(0x04040401,0x04000004), + CONST64(0x04040400,0x00040004), CONST64(0x04040401,0x00040004), CONST64(0x04040400,0x04040004), CONST64(0x04040401,0x04040004), + CONST64(0x04040400,0x00000404), CONST64(0x04040401,0x00000404), CONST64(0x04040400,0x04000404), CONST64(0x04040401,0x04000404), + CONST64(0x04040400,0x00040404), CONST64(0x04040401,0x00040404), CONST64(0x04040400,0x04040404), CONST64(0x04040401,0x04040404) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000004,0x00000000), CONST64(0x00000000,0x10000000), CONST64(0x00000004,0x10000000), + CONST64(0x00000000,0x00100000), CONST64(0x00000004,0x00100000), CONST64(0x00000000,0x10100000), CONST64(0x00000004,0x10100000), + CONST64(0x00000000,0x00001000), CONST64(0x00000004,0x00001000), CONST64(0x00000000,0x10001000), CONST64(0x00000004,0x10001000), + CONST64(0x00000000,0x00101000), CONST64(0x00000004,0x00101000), CONST64(0x00000000,0x10101000), CONST64(0x00000004,0x10101000), + CONST64(0x00000000,0x00000010), CONST64(0x00000004,0x00000010), CONST64(0x00000000,0x10000010), CONST64(0x00000004,0x10000010), + CONST64(0x00000000,0x00100010), CONST64(0x00000004,0x00100010), CONST64(0x00000000,0x10100010), CONST64(0x00000004,0x10100010), + CONST64(0x00000000,0x00001010), CONST64(0x00000004,0x00001010), CONST64(0x00000000,0x10001010), CONST64(0x00000004,0x10001010), + CONST64(0x00000000,0x00101010), CONST64(0x00000004,0x00101010), CONST64(0x00000000,0x10101010), CONST64(0x00000004,0x10101010), + CONST64(0x10000000,0x00000000), CONST64(0x10000004,0x00000000), CONST64(0x10000000,0x10000000), CONST64(0x10000004,0x10000000), + CONST64(0x10000000,0x00100000), CONST64(0x10000004,0x00100000), CONST64(0x10000000,0x10100000), CONST64(0x10000004,0x10100000), + CONST64(0x10000000,0x00001000), CONST64(0x10000004,0x00001000), CONST64(0x10000000,0x10001000), CONST64(0x10000004,0x10001000), + CONST64(0x10000000,0x00101000), CONST64(0x10000004,0x00101000), CONST64(0x10000000,0x10101000), CONST64(0x10000004,0x10101000), + CONST64(0x10000000,0x00000010), CONST64(0x10000004,0x00000010), CONST64(0x10000000,0x10000010), CONST64(0x10000004,0x10000010), + CONST64(0x10000000,0x00100010), CONST64(0x10000004,0x00100010), CONST64(0x10000000,0x10100010), CONST64(0x10000004,0x10100010), + CONST64(0x10000000,0x00001010), CONST64(0x10000004,0x00001010), CONST64(0x10000000,0x10001010), CONST64(0x10000004,0x10001010), + CONST64(0x10000000,0x00101010), CONST64(0x10000004,0x00101010), CONST64(0x10000000,0x10101010), CONST64(0x10000004,0x10101010), + CONST64(0x00100000,0x00000000), CONST64(0x00100004,0x00000000), CONST64(0x00100000,0x10000000), CONST64(0x00100004,0x10000000), + CONST64(0x00100000,0x00100000), CONST64(0x00100004,0x00100000), CONST64(0x00100000,0x10100000), CONST64(0x00100004,0x10100000), + CONST64(0x00100000,0x00001000), CONST64(0x00100004,0x00001000), CONST64(0x00100000,0x10001000), CONST64(0x00100004,0x10001000), + CONST64(0x00100000,0x00101000), CONST64(0x00100004,0x00101000), CONST64(0x00100000,0x10101000), CONST64(0x00100004,0x10101000), + CONST64(0x00100000,0x00000010), CONST64(0x00100004,0x00000010), CONST64(0x00100000,0x10000010), CONST64(0x00100004,0x10000010), + CONST64(0x00100000,0x00100010), CONST64(0x00100004,0x00100010), CONST64(0x00100000,0x10100010), CONST64(0x00100004,0x10100010), + CONST64(0x00100000,0x00001010), CONST64(0x00100004,0x00001010), CONST64(0x00100000,0x10001010), CONST64(0x00100004,0x10001010), + CONST64(0x00100000,0x00101010), CONST64(0x00100004,0x00101010), CONST64(0x00100000,0x10101010), CONST64(0x00100004,0x10101010), + CONST64(0x10100000,0x00000000), CONST64(0x10100004,0x00000000), CONST64(0x10100000,0x10000000), CONST64(0x10100004,0x10000000), + CONST64(0x10100000,0x00100000), CONST64(0x10100004,0x00100000), CONST64(0x10100000,0x10100000), CONST64(0x10100004,0x10100000), + CONST64(0x10100000,0x00001000), CONST64(0x10100004,0x00001000), CONST64(0x10100000,0x10001000), CONST64(0x10100004,0x10001000), + CONST64(0x10100000,0x00101000), CONST64(0x10100004,0x00101000), CONST64(0x10100000,0x10101000), CONST64(0x10100004,0x10101000), + CONST64(0x10100000,0x00000010), CONST64(0x10100004,0x00000010), CONST64(0x10100000,0x10000010), CONST64(0x10100004,0x10000010), + CONST64(0x10100000,0x00100010), CONST64(0x10100004,0x00100010), CONST64(0x10100000,0x10100010), CONST64(0x10100004,0x10100010), + CONST64(0x10100000,0x00001010), CONST64(0x10100004,0x00001010), CONST64(0x10100000,0x10001010), CONST64(0x10100004,0x10001010), + CONST64(0x10100000,0x00101010), CONST64(0x10100004,0x00101010), CONST64(0x10100000,0x10101010), CONST64(0x10100004,0x10101010), + CONST64(0x00001000,0x00000000), CONST64(0x00001004,0x00000000), CONST64(0x00001000,0x10000000), CONST64(0x00001004,0x10000000), + CONST64(0x00001000,0x00100000), CONST64(0x00001004,0x00100000), CONST64(0x00001000,0x10100000), CONST64(0x00001004,0x10100000), + CONST64(0x00001000,0x00001000), CONST64(0x00001004,0x00001000), CONST64(0x00001000,0x10001000), CONST64(0x00001004,0x10001000), + CONST64(0x00001000,0x00101000), CONST64(0x00001004,0x00101000), CONST64(0x00001000,0x10101000), CONST64(0x00001004,0x10101000), + CONST64(0x00001000,0x00000010), CONST64(0x00001004,0x00000010), CONST64(0x00001000,0x10000010), CONST64(0x00001004,0x10000010), + CONST64(0x00001000,0x00100010), CONST64(0x00001004,0x00100010), CONST64(0x00001000,0x10100010), CONST64(0x00001004,0x10100010), + CONST64(0x00001000,0x00001010), CONST64(0x00001004,0x00001010), CONST64(0x00001000,0x10001010), CONST64(0x00001004,0x10001010), + CONST64(0x00001000,0x00101010), CONST64(0x00001004,0x00101010), CONST64(0x00001000,0x10101010), CONST64(0x00001004,0x10101010), + CONST64(0x10001000,0x00000000), CONST64(0x10001004,0x00000000), CONST64(0x10001000,0x10000000), CONST64(0x10001004,0x10000000), + CONST64(0x10001000,0x00100000), CONST64(0x10001004,0x00100000), CONST64(0x10001000,0x10100000), CONST64(0x10001004,0x10100000), + CONST64(0x10001000,0x00001000), CONST64(0x10001004,0x00001000), CONST64(0x10001000,0x10001000), CONST64(0x10001004,0x10001000), + CONST64(0x10001000,0x00101000), CONST64(0x10001004,0x00101000), CONST64(0x10001000,0x10101000), CONST64(0x10001004,0x10101000), + CONST64(0x10001000,0x00000010), CONST64(0x10001004,0x00000010), CONST64(0x10001000,0x10000010), CONST64(0x10001004,0x10000010), + CONST64(0x10001000,0x00100010), CONST64(0x10001004,0x00100010), CONST64(0x10001000,0x10100010), CONST64(0x10001004,0x10100010), + CONST64(0x10001000,0x00001010), CONST64(0x10001004,0x00001010), CONST64(0x10001000,0x10001010), CONST64(0x10001004,0x10001010), + CONST64(0x10001000,0x00101010), CONST64(0x10001004,0x00101010), CONST64(0x10001000,0x10101010), CONST64(0x10001004,0x10101010), + CONST64(0x00101000,0x00000000), CONST64(0x00101004,0x00000000), CONST64(0x00101000,0x10000000), CONST64(0x00101004,0x10000000), + CONST64(0x00101000,0x00100000), CONST64(0x00101004,0x00100000), CONST64(0x00101000,0x10100000), CONST64(0x00101004,0x10100000), + CONST64(0x00101000,0x00001000), CONST64(0x00101004,0x00001000), CONST64(0x00101000,0x10001000), CONST64(0x00101004,0x10001000), + CONST64(0x00101000,0x00101000), CONST64(0x00101004,0x00101000), CONST64(0x00101000,0x10101000), CONST64(0x00101004,0x10101000), + CONST64(0x00101000,0x00000010), CONST64(0x00101004,0x00000010), CONST64(0x00101000,0x10000010), CONST64(0x00101004,0x10000010), + CONST64(0x00101000,0x00100010), CONST64(0x00101004,0x00100010), CONST64(0x00101000,0x10100010), CONST64(0x00101004,0x10100010), + CONST64(0x00101000,0x00001010), CONST64(0x00101004,0x00001010), CONST64(0x00101000,0x10001010), CONST64(0x00101004,0x10001010), + CONST64(0x00101000,0x00101010), CONST64(0x00101004,0x00101010), CONST64(0x00101000,0x10101010), CONST64(0x00101004,0x10101010), + CONST64(0x10101000,0x00000000), CONST64(0x10101004,0x00000000), CONST64(0x10101000,0x10000000), CONST64(0x10101004,0x10000000), + CONST64(0x10101000,0x00100000), CONST64(0x10101004,0x00100000), CONST64(0x10101000,0x10100000), CONST64(0x10101004,0x10100000), + CONST64(0x10101000,0x00001000), CONST64(0x10101004,0x00001000), CONST64(0x10101000,0x10001000), CONST64(0x10101004,0x10001000), + CONST64(0x10101000,0x00101000), CONST64(0x10101004,0x00101000), CONST64(0x10101000,0x10101000), CONST64(0x10101004,0x10101000), + CONST64(0x10101000,0x00000010), CONST64(0x10101004,0x00000010), CONST64(0x10101000,0x10000010), CONST64(0x10101004,0x10000010), + CONST64(0x10101000,0x00100010), CONST64(0x10101004,0x00100010), CONST64(0x10101000,0x10100010), CONST64(0x10101004,0x10100010), + CONST64(0x10101000,0x00001010), CONST64(0x10101004,0x00001010), CONST64(0x10101000,0x10001010), CONST64(0x10101004,0x10001010), + CONST64(0x10101000,0x00101010), CONST64(0x10101004,0x00101010), CONST64(0x10101000,0x10101010), CONST64(0x10101004,0x10101010) + }, +{ CONST64(0x00000000,0x00000000), CONST64(0x00000010,0x00000000), CONST64(0x00000000,0x40000000), CONST64(0x00000010,0x40000000), + CONST64(0x00000000,0x00400000), CONST64(0x00000010,0x00400000), CONST64(0x00000000,0x40400000), CONST64(0x00000010,0x40400000), + CONST64(0x00000000,0x00004000), CONST64(0x00000010,0x00004000), CONST64(0x00000000,0x40004000), CONST64(0x00000010,0x40004000), + CONST64(0x00000000,0x00404000), CONST64(0x00000010,0x00404000), CONST64(0x00000000,0x40404000), CONST64(0x00000010,0x40404000), + CONST64(0x00000000,0x00000040), CONST64(0x00000010,0x00000040), CONST64(0x00000000,0x40000040), CONST64(0x00000010,0x40000040), + CONST64(0x00000000,0x00400040), CONST64(0x00000010,0x00400040), CONST64(0x00000000,0x40400040), CONST64(0x00000010,0x40400040), + CONST64(0x00000000,0x00004040), CONST64(0x00000010,0x00004040), CONST64(0x00000000,0x40004040), CONST64(0x00000010,0x40004040), + CONST64(0x00000000,0x00404040), CONST64(0x00000010,0x00404040), CONST64(0x00000000,0x40404040), CONST64(0x00000010,0x40404040), + CONST64(0x40000000,0x00000000), CONST64(0x40000010,0x00000000), CONST64(0x40000000,0x40000000), CONST64(0x40000010,0x40000000), + CONST64(0x40000000,0x00400000), CONST64(0x40000010,0x00400000), CONST64(0x40000000,0x40400000), CONST64(0x40000010,0x40400000), + CONST64(0x40000000,0x00004000), CONST64(0x40000010,0x00004000), CONST64(0x40000000,0x40004000), CONST64(0x40000010,0x40004000), + CONST64(0x40000000,0x00404000), CONST64(0x40000010,0x00404000), CONST64(0x40000000,0x40404000), CONST64(0x40000010,0x40404000), + CONST64(0x40000000,0x00000040), CONST64(0x40000010,0x00000040), CONST64(0x40000000,0x40000040), CONST64(0x40000010,0x40000040), + CONST64(0x40000000,0x00400040), CONST64(0x40000010,0x00400040), CONST64(0x40000000,0x40400040), CONST64(0x40000010,0x40400040), + CONST64(0x40000000,0x00004040), CONST64(0x40000010,0x00004040), CONST64(0x40000000,0x40004040), CONST64(0x40000010,0x40004040), + CONST64(0x40000000,0x00404040), CONST64(0x40000010,0x00404040), CONST64(0x40000000,0x40404040), CONST64(0x40000010,0x40404040), + CONST64(0x00400000,0x00000000), CONST64(0x00400010,0x00000000), CONST64(0x00400000,0x40000000), CONST64(0x00400010,0x40000000), + CONST64(0x00400000,0x00400000), CONST64(0x00400010,0x00400000), CONST64(0x00400000,0x40400000), CONST64(0x00400010,0x40400000), + CONST64(0x00400000,0x00004000), CONST64(0x00400010,0x00004000), CONST64(0x00400000,0x40004000), CONST64(0x00400010,0x40004000), + CONST64(0x00400000,0x00404000), CONST64(0x00400010,0x00404000), CONST64(0x00400000,0x40404000), CONST64(0x00400010,0x40404000), + CONST64(0x00400000,0x00000040), CONST64(0x00400010,0x00000040), CONST64(0x00400000,0x40000040), CONST64(0x00400010,0x40000040), + CONST64(0x00400000,0x00400040), CONST64(0x00400010,0x00400040), CONST64(0x00400000,0x40400040), CONST64(0x00400010,0x40400040), + CONST64(0x00400000,0x00004040), CONST64(0x00400010,0x00004040), CONST64(0x00400000,0x40004040), CONST64(0x00400010,0x40004040), + CONST64(0x00400000,0x00404040), CONST64(0x00400010,0x00404040), CONST64(0x00400000,0x40404040), CONST64(0x00400010,0x40404040), + CONST64(0x40400000,0x00000000), CONST64(0x40400010,0x00000000), CONST64(0x40400000,0x40000000), CONST64(0x40400010,0x40000000), + CONST64(0x40400000,0x00400000), CONST64(0x40400010,0x00400000), CONST64(0x40400000,0x40400000), CONST64(0x40400010,0x40400000), + CONST64(0x40400000,0x00004000), CONST64(0x40400010,0x00004000), CONST64(0x40400000,0x40004000), CONST64(0x40400010,0x40004000), + CONST64(0x40400000,0x00404000), CONST64(0x40400010,0x00404000), CONST64(0x40400000,0x40404000), CONST64(0x40400010,0x40404000), + CONST64(0x40400000,0x00000040), CONST64(0x40400010,0x00000040), CONST64(0x40400000,0x40000040), CONST64(0x40400010,0x40000040), + CONST64(0x40400000,0x00400040), CONST64(0x40400010,0x00400040), CONST64(0x40400000,0x40400040), CONST64(0x40400010,0x40400040), + CONST64(0x40400000,0x00004040), CONST64(0x40400010,0x00004040), CONST64(0x40400000,0x40004040), CONST64(0x40400010,0x40004040), + CONST64(0x40400000,0x00404040), CONST64(0x40400010,0x00404040), CONST64(0x40400000,0x40404040), CONST64(0x40400010,0x40404040), + CONST64(0x00004000,0x00000000), CONST64(0x00004010,0x00000000), CONST64(0x00004000,0x40000000), CONST64(0x00004010,0x40000000), + CONST64(0x00004000,0x00400000), CONST64(0x00004010,0x00400000), CONST64(0x00004000,0x40400000), CONST64(0x00004010,0x40400000), + CONST64(0x00004000,0x00004000), CONST64(0x00004010,0x00004000), CONST64(0x00004000,0x40004000), CONST64(0x00004010,0x40004000), + CONST64(0x00004000,0x00404000), CONST64(0x00004010,0x00404000), CONST64(0x00004000,0x40404000), CONST64(0x00004010,0x40404000), + CONST64(0x00004000,0x00000040), CONST64(0x00004010,0x00000040), CONST64(0x00004000,0x40000040), CONST64(0x00004010,0x40000040), + CONST64(0x00004000,0x00400040), CONST64(0x00004010,0x00400040), CONST64(0x00004000,0x40400040), CONST64(0x00004010,0x40400040), + CONST64(0x00004000,0x00004040), CONST64(0x00004010,0x00004040), CONST64(0x00004000,0x40004040), CONST64(0x00004010,0x40004040), + CONST64(0x00004000,0x00404040), CONST64(0x00004010,0x00404040), CONST64(0x00004000,0x40404040), CONST64(0x00004010,0x40404040), + CONST64(0x40004000,0x00000000), CONST64(0x40004010,0x00000000), CONST64(0x40004000,0x40000000), CONST64(0x40004010,0x40000000), + CONST64(0x40004000,0x00400000), CONST64(0x40004010,0x00400000), CONST64(0x40004000,0x40400000), CONST64(0x40004010,0x40400000), + CONST64(0x40004000,0x00004000), CONST64(0x40004010,0x00004000), CONST64(0x40004000,0x40004000), CONST64(0x40004010,0x40004000), + CONST64(0x40004000,0x00404000), CONST64(0x40004010,0x00404000), CONST64(0x40004000,0x40404000), CONST64(0x40004010,0x40404000), + CONST64(0x40004000,0x00000040), CONST64(0x40004010,0x00000040), CONST64(0x40004000,0x40000040), CONST64(0x40004010,0x40000040), + CONST64(0x40004000,0x00400040), CONST64(0x40004010,0x00400040), CONST64(0x40004000,0x40400040), CONST64(0x40004010,0x40400040), + CONST64(0x40004000,0x00004040), CONST64(0x40004010,0x00004040), CONST64(0x40004000,0x40004040), CONST64(0x40004010,0x40004040), + CONST64(0x40004000,0x00404040), CONST64(0x40004010,0x00404040), CONST64(0x40004000,0x40404040), CONST64(0x40004010,0x40404040), + CONST64(0x00404000,0x00000000), CONST64(0x00404010,0x00000000), CONST64(0x00404000,0x40000000), CONST64(0x00404010,0x40000000), + CONST64(0x00404000,0x00400000), CONST64(0x00404010,0x00400000), CONST64(0x00404000,0x40400000), CONST64(0x00404010,0x40400000), + CONST64(0x00404000,0x00004000), CONST64(0x00404010,0x00004000), CONST64(0x00404000,0x40004000), CONST64(0x00404010,0x40004000), + CONST64(0x00404000,0x00404000), CONST64(0x00404010,0x00404000), CONST64(0x00404000,0x40404000), CONST64(0x00404010,0x40404000), + CONST64(0x00404000,0x00000040), CONST64(0x00404010,0x00000040), CONST64(0x00404000,0x40000040), CONST64(0x00404010,0x40000040), + CONST64(0x00404000,0x00400040), CONST64(0x00404010,0x00400040), CONST64(0x00404000,0x40400040), CONST64(0x00404010,0x40400040), + CONST64(0x00404000,0x00004040), CONST64(0x00404010,0x00004040), CONST64(0x00404000,0x40004040), CONST64(0x00404010,0x40004040), + CONST64(0x00404000,0x00404040), CONST64(0x00404010,0x00404040), CONST64(0x00404000,0x40404040), CONST64(0x00404010,0x40404040), + CONST64(0x40404000,0x00000000), CONST64(0x40404010,0x00000000), CONST64(0x40404000,0x40000000), CONST64(0x40404010,0x40000000), + CONST64(0x40404000,0x00400000), CONST64(0x40404010,0x00400000), CONST64(0x40404000,0x40400000), CONST64(0x40404010,0x40400000), + CONST64(0x40404000,0x00004000), CONST64(0x40404010,0x00004000), CONST64(0x40404000,0x40004000), CONST64(0x40404010,0x40004000), + CONST64(0x40404000,0x00404000), CONST64(0x40404010,0x00404000), CONST64(0x40404000,0x40404000), CONST64(0x40404010,0x40404000), + CONST64(0x40404000,0x00000040), CONST64(0x40404010,0x00000040), CONST64(0x40404000,0x40000040), CONST64(0x40404010,0x40000040), + CONST64(0x40404000,0x00400040), CONST64(0x40404010,0x00400040), CONST64(0x40404000,0x40400040), CONST64(0x40404010,0x40400040), + CONST64(0x40404000,0x00004040), CONST64(0x40404010,0x00004040), CONST64(0x40404000,0x40004040), CONST64(0x40404010,0x40004040), + CONST64(0x40404000,0x00404040), CONST64(0x40404010,0x00404040), CONST64(0x40404000,0x40404040), CONST64(0x40404010,0x40404040) + }}; + + +static void cookey(const ulong32 *raw1, ulong32 *keyout); + +static void deskey(const unsigned char *key, short edf, ulong32 *keyout) +{ + ulong32 i, j, l, m, n, kn[32]; + unsigned char pc1m[56], pcr[56]; + + for (j=0; j < 56; j++) { + l = (ulong32)pc1[j]; + m = l & 7; + pc1m[j] = (unsigned char)((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0); + } + + for (i=0; i < 16; i++) { + if (edf == DE1) { + m = (15 - i) << 1; + } else { + m = i << 1; + } + n = m + 1; + kn[m] = kn[n] = 0L; + for (j=0; j < 28; j++) { + l = j + (ulong32)totrot[i]; + if (l < 28) { + pcr[j] = pc1m[l]; + } else { + pcr[j] = pc1m[l - 28]; + } + } + for (/*j = 28*/; j < 56; j++) { + l = j + (ulong32)totrot[i]; + if (l < 56) { + pcr[j] = pc1m[l]; + } else { + pcr[j] = pc1m[l - 28]; + } + } + for (j=0; j < 24; j++) { + if ((int)pcr[(int)pc2[j]] != 0) { + kn[m] |= bigbyte[j]; + } + if ((int)pcr[(int)pc2[j+24]] != 0) { + kn[n] |= bigbyte[j]; + } + } + } + + cookey(kn, keyout); +} + +static void cookey(const ulong32 *raw1, ulong32 *keyout) +{ + ulong32 *cook; + const ulong32 *raw0; + ulong32 dough[32]; + int i; + + cook = dough; + for(i=0; i < 16; i++, raw1++) + { + raw0 = raw1++; + *cook = (*raw0 & 0x00fc0000L) << 6; + *cook |= (*raw0 & 0x00000fc0L) << 10; + *cook |= (*raw1 & 0x00fc0000L) >> 10; + *cook++ |= (*raw1 & 0x00000fc0L) >> 6; + *cook = (*raw0 & 0x0003f000L) << 12; + *cook |= (*raw0 & 0x0000003fL) << 16; + *cook |= (*raw1 & 0x0003f000L) >> 4; + *cook++ |= (*raw1 & 0x0000003fL); + } + + memcpy(keyout, dough, sizeof dough); +} + +static void desfunc(ulong32 *block, const ulong32 *keys) +{ + ulong64 tmp; + ulong32 work, right, leftt; + int cur_round; + + leftt = block[0]; + right = block[1]; + + tmp = des_ip[0][byte(leftt, 0)] ^ + des_ip[1][byte(leftt, 1)] ^ + des_ip[2][byte(leftt, 2)] ^ + des_ip[3][byte(leftt, 3)] ^ + des_ip[4][byte(right, 0)] ^ + des_ip[5][byte(right, 1)] ^ + des_ip[6][byte(right, 2)] ^ + des_ip[7][byte(right, 3)]; + leftt = (ulong32)(tmp >> 32); + right = (ulong32)(tmp & 0xFFFFFFFFUL); + + for (cur_round = 0; cur_round < 8; cur_round++) { + work = ROR(right, 4) ^ *keys++; + leftt ^= SP7[work & 0x3fL] + ^ SP5[(work >> 8) & 0x3fL] + ^ SP3[(work >> 16) & 0x3fL] + ^ SP1[(work >> 24) & 0x3fL]; + work = right ^ *keys++; + leftt ^= SP8[ work & 0x3fL] + ^ SP6[(work >> 8) & 0x3fL] + ^ SP4[(work >> 16) & 0x3fL] + ^ SP2[(work >> 24) & 0x3fL]; + + work = ROR(leftt, 4) ^ *keys++; + right ^= SP7[ work & 0x3fL] + ^ SP5[(work >> 8) & 0x3fL] + ^ SP3[(work >> 16) & 0x3fL] + ^ SP1[(work >> 24) & 0x3fL]; + work = leftt ^ *keys++; + right ^= SP8[ work & 0x3fL] + ^ SP6[(work >> 8) & 0x3fL] + ^ SP4[(work >> 16) & 0x3fL] + ^ SP2[(work >> 24) & 0x3fL]; + } + + tmp = des_fp[0][byte(leftt, 0)] ^ + des_fp[1][byte(leftt, 1)] ^ + des_fp[2][byte(leftt, 2)] ^ + des_fp[3][byte(leftt, 3)] ^ + des_fp[4][byte(right, 0)] ^ + des_fp[5][byte(right, 1)] ^ + des_fp[6][byte(right, 2)] ^ + des_fp[7][byte(right, 3)]; + leftt = (ulong32)(tmp >> 32); + right = (ulong32)(tmp & 0xFFFFFFFFUL); + + block[0] = right; + block[1] = leftt; +} + +int des_setup(const unsigned char *key, int keylen, int num_rounds, des_key *des) +{ + if (num_rounds != 0 && num_rounds != 16) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 8) { + return CRYPT_INVALID_KEYSIZE; + } + + deskey(key, EN0, des->ek); + deskey(key, DE1, des->dk); + + return CRYPT_OK; +} + +int des3_setup(const unsigned char *key, int keylen, int num_rounds, des3_key *des3) +{ + if(num_rounds != 0 && num_rounds != 16) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 24) { + return CRYPT_INVALID_KEYSIZE; + } + + deskey(key, EN0, des3->ek[0]); + deskey(key+8, DE1, des3->ek[1]); + deskey(key+16, EN0, des3->ek[2]); + + deskey(key, DE1, des3->dk[2]); + deskey(key+8, EN0, des3->dk[1]); + deskey(key+16, DE1, des3->dk[0]); + + return CRYPT_OK; +} + +void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const des_key *des) +{ + ulong32 work[2]; + LOAD32H(work[0], pt+0); + LOAD32H(work[1], pt+4); + desfunc(work, des->ek); + STORE32H(work[0],ct+0); + STORE32H(work[1],ct+4); +} + +void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const des_key *des) +{ + ulong32 work[2]; + LOAD32H(work[0], ct+0); + LOAD32H(work[1], ct+4); + desfunc(work, des->dk); + STORE32H(work[0],pt+0); + STORE32H(work[1],pt+4); +} + +void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const des3_key *des3) +{ + ulong32 work[2]; + LOAD32H(work[0], pt+0); + LOAD32H(work[1], pt+4); + desfunc(work, des3->ek[0]); + desfunc(work, des3->ek[1]); + desfunc(work, des3->ek[2]); + STORE32H(work[0],ct+0); + STORE32H(work[1],ct+4); +} + +void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const des3_key *des3) +{ + ulong32 work[2]; + LOAD32H(work[0], ct+0); + LOAD32H(work[1], ct+4); + desfunc(work, des3->dk[0]); + desfunc(work, des3->dk[1]); + desfunc(work, des3->dk[2]); + STORE32H(work[0],pt+0); + STORE32H(work[1],pt+4); +} diff --git a/reactos/dll/win32/rsaenh/handle.c b/reactos/dll/win32/rsaenh/handle.c new file mode 100644 index 00000000000..fc4c717ff8b --- /dev/null +++ b/reactos/dll/win32/rsaenh/handle.c @@ -0,0 +1,456 @@ +/* + * dlls/rsaenh/handle.c + * Support code to manage HANDLE tables. + * + * Copyright 1998 Alexandre Julliard + * Copyright 2002-2004 Mike McCormack for CodeWeavers + * Copyright 2004 Michael Jung + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "handle.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(handle); + +#define HANDLE2INDEX(h) ((h)-1) +#define INDEX2HANDLE(i) ((i)+1) + +/****************************************************************************** + * init_handle_table + * + * Initializes the HANDLETABLE structure pointed to by lpTable + * + * PARAMS + * lpTable [I] Pointer to the HANDLETABLE structure, which is to be initalized. + * + * NOTES + * Note that alloc_handle_table calls init_handle_table on it's own, which + * means that you only have to call init_handle_table, if you use a global + * variable of type HANDLETABLE for your handle table. However, in this + * case you have to call destroy_handle_table when you don't need the table + * any more. + */ +void init_handle_table(HANDLETABLE *lpTable) +{ + TRACE("(lpTable=%p)\n", lpTable); + + lpTable->paEntries = NULL; + lpTable->iEntries = 0; + lpTable->iFirstFree = 0; + InitializeCriticalSection(&lpTable->mutex); + lpTable->mutex.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": HANDLETABLE.mutex"); +} + +/****************************************************************************** + * destroy_handle_table + * + * Destroys the handle table. + * + * PARAMS + * lpTable [I] Pointer to the handle table, which is to be destroyed. + * + * NOTES + * Note that release_handle_table takes care of this. + */ +void destroy_handle_table(HANDLETABLE *lpTable) +{ + TRACE("(lpTable=%p)\n", lpTable); + + HeapFree(GetProcessHeap(), 0, lpTable->paEntries); + lpTable->mutex.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&lpTable->mutex); +} + +/****************************************************************************** + * is_valid_handle + * + * Tests if handle is valid given the specified handle table + * + * PARAMS + * lpTable [I] Pointer to the handle table, with respect to which the handle's + * validness is tested. + * handle [I] The handle tested for validness. + * dwType [I] A magic value that identifies the referenced object's type. + * + * RETURNS + * non zero, if handle is valid. + * zero, if handle is not valid. + */ +int is_valid_handle(HANDLETABLE *lpTable, HCRYPTKEY handle, DWORD dwType) +{ + unsigned int index = HANDLE2INDEX(handle); + int ret = 0; + + TRACE("(lpTable=%p, handle=%ld)\n", lpTable, handle); + + EnterCriticalSection(&lpTable->mutex); + + /* We don't use zero handle values */ + if (!handle) goto exit; + + /* Check for index out of table bounds */ + if (index >= lpTable->iEntries) goto exit; + + /* Check if this handle is currently allocated */ + if (!lpTable->paEntries[index].pObject) goto exit; + + /* Check if this handle references an object of the correct type. */ + if (lpTable->paEntries[index].pObject->dwType != dwType) goto exit; + + ret = 1; +exit: + LeaveCriticalSection(&lpTable->mutex); + return ret; +} + +/****************************************************************************** + * release_all_handles + * + * Releases all valid handles in the given handle table and shrinks the table + * to zero size. + * + * PARAMS + * lpTable [I] The table of which all valid handles shall be released. + */ +static void release_all_handles(HANDLETABLE *lpTable) +{ + unsigned int i; + + TRACE("(lpTable=%p)\n", lpTable); + + EnterCriticalSection(&lpTable->mutex); + for (i=0; iiEntries; i++) + if (lpTable->paEntries[i].pObject) + release_handle(lpTable, lpTable->paEntries[i].pObject->dwType, INDEX2HANDLE(i)); + LeaveCriticalSection(&lpTable->mutex); +} + +/****************************************************************************** + * alloc_handle_table + * + * Allocates a new handle table + * + * PARAMS + * lplpTable [O] Pointer to the variable, to which the pointer to the newly + * allocated handle table is written. + * RETURNS + * non zero, if successful + * zero, if not successful (out of process heap memory) + * + * NOTES + * If all you need is a single handle table, you may as well declare a global + * variable of type HANDLETABLE and call init_handle_table on your own. + */ +int alloc_handle_table(HANDLETABLE **lplpTable) +{ + TRACE("(lplpTable=%p)\n", lplpTable); + + *lplpTable = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLETABLE)); + if (*lplpTable) + { + init_handle_table(*lplpTable); + return 1; + } + else + return 0; +} + +/****************************************************************************** + * release_handle_table + * + * Releases a handle table and frees the resources it used. + * + * PARAMS + * lpTable [I] Pointer to the handle table, which is to be released. + * + * RETURNS + * non zero, if successful + * zero, if not successful + * + * NOTES + * All valid handles still in the table are released also. + */ +int release_handle_table(HANDLETABLE *lpTable) +{ + TRACE("(lpTable=%p)\n", lpTable); + + release_all_handles(lpTable); + destroy_handle_table(lpTable); + return (int)HeapFree(GetProcessHeap(), 0, lpTable); +} + +/****************************************************************************** + * grow_handle_table [Internal] + * + * Grows the number of entries in the given table by TABLE_SIZE_INCREMENT + * + * PARAMS + * lpTable [I] Pointer to the table, which is to be grown + * + * RETURNS + * non zero, if successful + * zero, if not successful (out of memory on process heap) + * + * NOTES + * This is a support function for alloc_handle. Do not call! + */ +static int grow_handle_table(HANDLETABLE *lpTable) +{ + HANDLETABLEENTRY *newEntries; + unsigned int i, newIEntries; + + newIEntries = lpTable->iEntries + TABLE_SIZE_INCREMENT; + + newEntries = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLETABLEENTRY)*newIEntries); + if (!newEntries) + return 0; + + if (lpTable->paEntries) + { + memcpy(newEntries, lpTable->paEntries, sizeof(HANDLETABLEENTRY)*lpTable->iEntries); + HeapFree(GetProcessHeap(), 0, lpTable->paEntries); + } + + for (i=lpTable->iEntries; ipaEntries = newEntries; + lpTable->iEntries = newIEntries; + + return 1; +} + +/****************************************************************************** + * alloc_handle + * + * Allocates a new handle to the specified object in a given handle table. + * + * PARAMS + * lpTable [I] Pointer to the handle table, from which the new handle is + * allocated. + * lpObject [I] Pointer to the object, for which a handle shall be allocated. + * lpHandle [O] Pointer to a handle variable, into which the handle value will + * be stored. If not successful, this will be + * INVALID_HANDLE_VALUE + * RETURNS + * non zero, if successful + * zero, if not successful (no free handle) + */ +static int alloc_handle(HANDLETABLE *lpTable, OBJECTHDR *lpObject, HCRYPTKEY *lpHandle) +{ + int ret = 0; + + TRACE("(lpTable=%p, lpObject=%p, lpHandle=%p)\n", lpTable, lpObject, lpHandle); + + EnterCriticalSection(&lpTable->mutex); + if (lpTable->iFirstFree >= lpTable->iEntries) + if (!grow_handle_table(lpTable)) + { + *lpHandle = (HCRYPTKEY)INVALID_HANDLE_VALUE; + goto exit; + } + + *lpHandle = INDEX2HANDLE(lpTable->iFirstFree); + + lpTable->paEntries[lpTable->iFirstFree].pObject = lpObject; + lpTable->iFirstFree = lpTable->paEntries[lpTable->iFirstFree].iNextFree; + InterlockedIncrement(&lpObject->refcount); + + ret = 1; +exit: + LeaveCriticalSection(&lpTable->mutex); + return ret; +} + +/****************************************************************************** + * release_handle + * + * Releases resources occupied by the specified handle in the given table. + * The reference count of the handled object is decremented. If it becomes + * zero and if the 'destructor' function pointer member is non NULL, the + * destructor function will be called. Note that release_handle does not + * release resources other than the handle itself. If this is wanted, do it + * in the destructor function. + * + * PARAMS + * lpTable [I] Pointer to the handle table, from which a handle is to be + * released. + * handle [I] The handle, which is to be released + * dwType [I] Identifier for the type of the object, for which a handle is + * to be released. + * + * RETURNS + * non zero, if successful + * zero, if not successful (invalid handle) + */ +int release_handle(HANDLETABLE *lpTable, HCRYPTKEY handle, DWORD dwType) +{ + unsigned int index = HANDLE2INDEX(handle); + OBJECTHDR *pObject; + int ret = 0; + + TRACE("(lpTable=%p, handle=%ld)\n", lpTable, handle); + + EnterCriticalSection(&lpTable->mutex); + + if (!is_valid_handle(lpTable, handle, dwType)) + goto exit; + + pObject = lpTable->paEntries[index].pObject; + if (InterlockedDecrement(&pObject->refcount) == 0) + { + TRACE("destroying handle %ld\n", handle); + if (pObject->destructor) + pObject->destructor(pObject); + } + + lpTable->paEntries[index].pObject = NULL; + lpTable->paEntries[index].iNextFree = lpTable->iFirstFree; + lpTable->iFirstFree = index; + + ret = 1; +exit: + LeaveCriticalSection(&lpTable->mutex); + return ret; +} + +/****************************************************************************** + * lookup_handle + * + * Returns the object identified by the handle in the given handle table + * + * PARAMS + * lpTable [I] Pointer to the handle table, in which the handle is looked up. + * handle [I] The handle, which is to be looked up + * lplpObject [O] Pointer to the variable, into which the pointer to the + * object looked up is copied. + * RETURNS + * non zero, if successful + * zero, if not successful (invalid handle) + */ +int lookup_handle(HANDLETABLE *lpTable, HCRYPTKEY handle, DWORD dwType, OBJECTHDR **lplpObject) +{ + int ret = 0; + + TRACE("(lpTable=%p, handle=%ld, lplpObject=%p)\n", lpTable, handle, lplpObject); + + EnterCriticalSection(&lpTable->mutex); + if (!is_valid_handle(lpTable, handle, dwType)) + { + *lplpObject = NULL; + goto exit; + } + *lplpObject = lpTable->paEntries[HANDLE2INDEX(handle)].pObject; + + ret = 1; +exit: + LeaveCriticalSection(&lpTable->mutex); + return ret; +} + +/****************************************************************************** + * copy_handle + * + * Copies a handle. Increments the reference count of the object referenced + * by the handle. + * + * PARAMS + * lpTable [I] Pointer to the handle table, which holds the handle to be copied. + * handle [I] The handle to be copied. + * copy [O] Pointer to a handle variable, where the copied handle is put. + * + * RETURNS + * non zero, if successful + * zero, if not successful (invalid handle or out of memory) + */ +int copy_handle(HANDLETABLE *lpTable, HCRYPTKEY handle, DWORD dwType, HCRYPTKEY *copy) +{ + OBJECTHDR *pObject; + int ret; + + TRACE("(lpTable=%p, handle=%ld, copy=%p)\n", lpTable, handle, copy); + + EnterCriticalSection(&lpTable->mutex); + if (!lookup_handle(lpTable, handle, dwType, &pObject)) + { + *copy = (HCRYPTKEY)INVALID_HANDLE_VALUE; + LeaveCriticalSection(&lpTable->mutex); + return 0; + } + + ret = alloc_handle(lpTable, pObject, copy); + LeaveCriticalSection(&lpTable->mutex); + return ret; +} + +/****************************************************************************** + * new_object + * + * Allocates a new object of size cbSize on the current process's heap. + * Initializes the object header using the destructor and dwType params. + * Allocates a handle to the object in the handle table pointed to by lpTable. + * Returns a pointer to the created object in ppObject. + * Returns a handle to the created object. + * + * PARAMS + * lpTable [I] Pointer to the handle table, from which a handle is to be + * allocated. + * cbSize [I] Size of the object to be allocated in bytes. + * dwType [I] Object type; will be copied to the object header. + * destructor [I] Function pointer to a destructor function. Will be called + * once the object's reference count gets zero. + * ppObject [O] Pointer to a pointer variable, where a pointer to the newly + * created object will be stored. You may set this to NULL. + * + * RETURNS + * INVALID_HANDLE_VALUE, if something went wrong. + * a handle to the new object, if successful. + */ +HCRYPTKEY new_object(HANDLETABLE *lpTable, size_t cbSize, DWORD dwType, DESTRUCTOR destructor, + OBJECTHDR **ppObject) +{ + OBJECTHDR *pObject; + HCRYPTKEY hObject; + + if (ppObject) + *ppObject = NULL; + + pObject = HeapAlloc(GetProcessHeap(), 0, cbSize); + if (!pObject) + return (HCRYPTKEY)INVALID_HANDLE_VALUE; + + pObject->dwType = dwType; + pObject->refcount = 0; + pObject->destructor = destructor; + + if (!alloc_handle(lpTable, pObject, &hObject)) + HeapFree(GetProcessHeap(), 0, pObject); + else + if (ppObject) + *ppObject = pObject; + + return hObject; +} diff --git a/reactos/dll/win32/rsaenh/handle.h b/reactos/dll/win32/rsaenh/handle.h new file mode 100644 index 00000000000..b0adef87321 --- /dev/null +++ b/reactos/dll/win32/rsaenh/handle.h @@ -0,0 +1,79 @@ +/* + * dlls/rsaenh/handle.h + * Support code to manage HANDLE tables. + * + * Copyright 1998 Alexandre Julliard + * Copyright 2002-2004 Mike McCormack for CodeWeavers + * Copyright 2004 Michael Jung + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_HANDLE_H +#define __WINE_HANDLE_H + +#include "wincrypt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TABLE_SIZE_INCREMENT 32 + +struct tagOBJECTHDR; +typedef struct tagOBJECTHDR OBJECTHDR; +typedef void (*DESTRUCTOR)(OBJECTHDR *object); +struct tagOBJECTHDR +{ + DWORD dwType; + LONG refcount; + DESTRUCTOR destructor; +}; + +typedef struct tagHANDLETABLEENTRY +{ + OBJECTHDR *pObject; + unsigned int iNextFree; +} HANDLETABLEENTRY; + +/* Prevent conflict with wingdi.h */ +#define tagHANDLETABLE tagHANDLETABLE_RSA +#define HANDLETABLE HANDLETABLE_RSA + +typedef struct tagHANDLETABLE +{ + unsigned int iEntries; + unsigned int iFirstFree; + HANDLETABLEENTRY *paEntries; + CRITICAL_SECTION mutex; +} HANDLETABLE; + +int alloc_handle_table (HANDLETABLE **lplpTable); +void init_handle_table (HANDLETABLE *lpTable); +int release_handle_table(HANDLETABLE *lpTable); +void destroy_handle_table(HANDLETABLE *lpTable); +int release_handle (HANDLETABLE *lpTable, HCRYPTKEY handle, DWORD dwType); +int copy_handle (HANDLETABLE *lpTable, HCRYPTKEY handle, DWORD dwType, HCRYPTKEY *copy); +int lookup_handle (HANDLETABLE *lpTable, HCRYPTKEY handle, DWORD dwType, OBJECTHDR **lplpObject); +int is_valid_handle (HANDLETABLE *lpTable, HCRYPTKEY handle, DWORD dwType); + +HCRYPTKEY new_object (HANDLETABLE *lpTable, size_t cbSize, DWORD dwType, DESTRUCTOR destructor, + OBJECTHDR **ppObject); + +#ifdef __cplusplus +} +#endif + +#endif /* __WINE_HANDLE_H */ diff --git a/reactos/dll/win32/rsaenh/implglue.c b/reactos/dll/win32/rsaenh/implglue.c new file mode 100644 index 00000000000..d31f615eff0 --- /dev/null +++ b/reactos/dll/win32/rsaenh/implglue.c @@ -0,0 +1,437 @@ +/* + * dlls/rsaenh/implglue.c + * Glueing the RSAENH specific code to the crypto library + * + * Copyright (c) 2004, 2005 Michael Jung + * + * based on code by Mike McCormack and David Hammerton + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include "config.h" + +#include "wine/port.h" +#include "wine/library.h" + +#include "windef.h" +#include "wincrypt.h" + +#include "implglue.h" + +#include + +/* Function prototypes copied from dlls/advapi32/crypt_md4.c */ +VOID WINAPI MD4Init( MD4_CTX *ctx ); +VOID WINAPI MD4Update( MD4_CTX *ctx, const unsigned char *buf, unsigned int len ); +VOID WINAPI MD4Final( MD4_CTX *ctx ); +/* Function prototypes copied from dlls/advapi32/crypt_md5.c */ +VOID WINAPI MD5Init( MD5_CTX *ctx ); +VOID WINAPI MD5Update( MD5_CTX *ctx, const unsigned char *buf, unsigned int len ); +VOID WINAPI MD5Final( MD5_CTX *ctx ); +/* Function prototypes copied from dlls/advapi32/crypt_sha.c */ +VOID WINAPI A_SHAInit(PSHA_CTX Context); +VOID WINAPI A_SHAUpdate(PSHA_CTX Context, const unsigned char *Buffer, UINT BufferSize); +VOID WINAPI A_SHAFinal(PSHA_CTX Context, PULONG Result); +/* Function prototype copied from dlls/advapi32/crypt.c */ +BOOL WINAPI SystemFunction036(PVOID pbBuffer, ULONG dwLen); + +BOOL init_hash_impl(ALG_ID aiAlgid, HASH_CONTEXT *pHashContext) +{ + switch (aiAlgid) + { + case CALG_MD2: + md2_init(&pHashContext->md2); + break; + + case CALG_MD4: + MD4Init(&pHashContext->md4); + break; + + case CALG_MD5: + MD5Init(&pHashContext->md5); + break; + + case CALG_SHA: + A_SHAInit(&pHashContext->sha); + break; + } + + return TRUE; +} + +BOOL update_hash_impl(ALG_ID aiAlgid, HASH_CONTEXT *pHashContext, CONST BYTE *pbData, + DWORD dwDataLen) +{ + switch (aiAlgid) + { + case CALG_MD2: + md2_process(&pHashContext->md2, pbData, dwDataLen); + break; + + case CALG_MD4: + MD4Update(&pHashContext->md4, pbData, dwDataLen); + break; + + case CALG_MD5: + MD5Update(&pHashContext->md5, pbData, dwDataLen); + break; + + case CALG_SHA: + A_SHAUpdate(&pHashContext->sha, pbData, dwDataLen); + break; + + default: + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + + return TRUE; +} + +BOOL finalize_hash_impl(ALG_ID aiAlgid, HASH_CONTEXT *pHashContext, BYTE *pbHashValue) +{ + switch (aiAlgid) + { + case CALG_MD2: + md2_done(&pHashContext->md2, pbHashValue); + break; + + case CALG_MD4: + MD4Final(&pHashContext->md4); + memcpy(pbHashValue, pHashContext->md4.digest, 16); + break; + + case CALG_MD5: + MD5Final(&pHashContext->md5); + memcpy(pbHashValue, pHashContext->md5.digest, 16); + break; + + case CALG_SHA: + A_SHAFinal(&pHashContext->sha, (PULONG)pbHashValue); + break; + + default: + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + + return TRUE; +} + +BOOL duplicate_hash_impl(ALG_ID aiAlgid, CONST HASH_CONTEXT *pSrcHashContext, + HASH_CONTEXT *pDestHashContext) +{ + memcpy(pDestHashContext, pSrcHashContext, sizeof(HASH_CONTEXT)); + + return TRUE; +} + +BOOL new_key_impl(ALG_ID aiAlgid, KEY_CONTEXT *pKeyContext, DWORD dwKeyLen) +{ + switch (aiAlgid) + { + case CALG_RSA_KEYX: + case CALG_RSA_SIGN: + if (rsa_make_key((int)dwKeyLen, 65537, &pKeyContext->rsa) != CRYPT_OK) { + SetLastError(NTE_FAIL); + return FALSE; + } + return TRUE; + } + + return TRUE; +} + +BOOL free_key_impl(ALG_ID aiAlgid, KEY_CONTEXT *pKeyContext) +{ + switch (aiAlgid) + { + case CALG_RSA_KEYX: + case CALG_RSA_SIGN: + rsa_free(&pKeyContext->rsa); + } + + return TRUE; +} + +BOOL setup_key_impl(ALG_ID aiAlgid, KEY_CONTEXT *pKeyContext, DWORD dwKeyLen, + DWORD dwEffectiveKeyLen, DWORD dwSaltLen, BYTE *abKeyValue) +{ + switch (aiAlgid) + { + case CALG_RC4: + rc4_start(&pKeyContext->rc4); + rc4_add_entropy(abKeyValue, dwKeyLen + dwSaltLen, &pKeyContext->rc4); + rc4_ready(&pKeyContext->rc4); + break; + + case CALG_RC2: + rc2_setup(abKeyValue, dwKeyLen + dwSaltLen, dwEffectiveKeyLen ? + dwEffectiveKeyLen : dwKeyLen << 3, 0, &pKeyContext->rc2); + break; + + case CALG_3DES: + des3_setup(abKeyValue, 24, 0, &pKeyContext->des3); + break; + + case CALG_3DES_112: + memcpy(abKeyValue+16, abKeyValue, 8); + des3_setup(abKeyValue, 24, 0, &pKeyContext->des3); + break; + + case CALG_DES: + des_setup(abKeyValue, 8, 0, &pKeyContext->des); + break; + } + + return TRUE; +} + +BOOL duplicate_key_impl(ALG_ID aiAlgid, CONST KEY_CONTEXT *pSrcKeyContext, + KEY_CONTEXT *pDestKeyContext) +{ + switch (aiAlgid) + { + case CALG_RC4: + case CALG_RC2: + case CALG_3DES: + case CALG_3DES_112: + case CALG_DES: + memcpy(pDestKeyContext, pSrcKeyContext, sizeof(KEY_CONTEXT)); + break; + case CALG_RSA_KEYX: + case CALG_RSA_SIGN: + pDestKeyContext->rsa.type = pSrcKeyContext->rsa.type; + mp_init_copy(&pDestKeyContext->rsa.e, &pSrcKeyContext->rsa.e); + mp_init_copy(&pDestKeyContext->rsa.d, &pSrcKeyContext->rsa.d); + mp_init_copy(&pDestKeyContext->rsa.N, &pSrcKeyContext->rsa.N); + mp_init_copy(&pDestKeyContext->rsa.p, &pSrcKeyContext->rsa.p); + mp_init_copy(&pDestKeyContext->rsa.q, &pSrcKeyContext->rsa.q); + mp_init_copy(&pDestKeyContext->rsa.qP, &pSrcKeyContext->rsa.qP); + mp_init_copy(&pDestKeyContext->rsa.dP, &pSrcKeyContext->rsa.dP); + mp_init_copy(&pDestKeyContext->rsa.dQ, &pSrcKeyContext->rsa.dQ); + break; + + default: + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + + return TRUE; +} + +static inline void reverse_bytes(BYTE *pbData, DWORD dwLen) { + BYTE swap; + DWORD i; + + for (i=0; irc2); + } else { + rc2_ecb_decrypt(in, out, &pKeyContext->rc2); + } + break; + + case CALG_3DES: + case CALG_3DES_112: + if (enc) { + des3_ecb_encrypt(in, out, &pKeyContext->des3); + } else { + des3_ecb_decrypt(in, out, &pKeyContext->des3); + } + break; + + case CALG_DES: + if (enc) { + des_ecb_encrypt(in, out, &pKeyContext->des); + } else { + des_ecb_decrypt(in, out, &pKeyContext->des); + } + break; + + case CALG_RSA_KEYX: + case CALG_RSA_SIGN: + outlen = inlen = (mp_count_bits(&pKeyContext->rsa.N)+7)/8; + if (enc) { + if (rsa_exptmod(in, inlen, out, &outlen, dwKeySpec, &pKeyContext->rsa) != CRYPT_OK) { + SetLastError(NTE_FAIL); + return FALSE; + } + reverse_bytes(out, outlen); + } else { + in_reversed = HeapAlloc(GetProcessHeap(), 0, inlen); + if (!in_reversed) { + SetLastError(NTE_NO_MEMORY); + return FALSE; + } + memcpy(in_reversed, in, inlen); + reverse_bytes(in_reversed, inlen); + if (rsa_exptmod(in_reversed, inlen, out, &outlen, dwKeySpec, &pKeyContext->rsa) != CRYPT_OK) { + HeapFree(GetProcessHeap(), 0, in_reversed); + SetLastError(NTE_FAIL); + return FALSE; + } + HeapFree(GetProcessHeap(), 0, in_reversed); + } + break; + + default: + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + + return TRUE; +} + +BOOL encrypt_stream_impl(ALG_ID aiAlgid, KEY_CONTEXT *pKeyContext, BYTE *stream, DWORD dwLen) +{ + switch (aiAlgid) { + case CALG_RC4: + rc4_read(stream, dwLen, &pKeyContext->rc4); + break; + + default: + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + + return TRUE; +} + +BOOL gen_rand_impl(BYTE *pbBuffer, DWORD dwLen) +{ + return SystemFunction036(pbBuffer, dwLen); +} + +BOOL export_public_key_impl(BYTE *pbDest, const KEY_CONTEXT *pKeyContext, DWORD dwKeyLen,DWORD *pdwPubExp) +{ + mp_to_unsigned_bin(&pKeyContext->rsa.N, pbDest); + reverse_bytes(pbDest, dwKeyLen); + *pdwPubExp = (DWORD)mp_get_int(&pKeyContext->rsa.e); + return TRUE; +} + +BOOL import_public_key_impl(CONST BYTE *pbSrc, KEY_CONTEXT *pKeyContext, DWORD dwKeyLen, + DWORD dwPubExp) +{ + BYTE *pbTemp; + + if (mp_init_multi(&pKeyContext->rsa.e, &pKeyContext->rsa.d, &pKeyContext->rsa.N, + &pKeyContext->rsa.dQ,&pKeyContext->rsa.dP,&pKeyContext->rsa.qP, + &pKeyContext->rsa.p, &pKeyContext->rsa.q, NULL) != MP_OKAY) + { + SetLastError(NTE_FAIL); + return FALSE; + } + + pbTemp = HeapAlloc(GetProcessHeap(), 0, dwKeyLen); + if (!pbTemp) return FALSE; + memcpy(pbTemp, pbSrc, dwKeyLen); + + pKeyContext->rsa.type = PK_PUBLIC; + reverse_bytes(pbTemp, dwKeyLen); + mp_read_unsigned_bin(&pKeyContext->rsa.N, pbTemp, dwKeyLen); + HeapFree(GetProcessHeap(), 0, pbTemp); + mp_set_int(&pKeyContext->rsa.e, dwPubExp); + + return TRUE; +} + +BOOL export_private_key_impl(BYTE *pbDest, const KEY_CONTEXT *pKeyContext, DWORD dwKeyLen, + DWORD *pdwPubExp) +{ + mp_to_unsigned_bin(&pKeyContext->rsa.N, pbDest); + reverse_bytes(pbDest, dwKeyLen); + pbDest += dwKeyLen; + mp_to_unsigned_bin(&pKeyContext->rsa.p, pbDest); + reverse_bytes(pbDest, (dwKeyLen+1)>>1); + pbDest += (dwKeyLen+1)>>1; + mp_to_unsigned_bin(&pKeyContext->rsa.q, pbDest); + reverse_bytes(pbDest, (dwKeyLen+1)>>1); + pbDest += (dwKeyLen+1)>>1; + mp_to_unsigned_bin(&pKeyContext->rsa.dP, pbDest); + reverse_bytes(pbDest, (dwKeyLen+1)>>1); + pbDest += (dwKeyLen+1)>>1; + mp_to_unsigned_bin(&pKeyContext->rsa.dQ, pbDest); + reverse_bytes(pbDest, (dwKeyLen+1)>>1); + pbDest += (dwKeyLen+1)>>1; + mp_to_unsigned_bin(&pKeyContext->rsa.qP, pbDest); + reverse_bytes(pbDest, (dwKeyLen+1)>>1); + pbDest += (dwKeyLen+1)>>1; + mp_to_unsigned_bin(&pKeyContext->rsa.d, pbDest); + reverse_bytes(pbDest, dwKeyLen); + *pdwPubExp = (DWORD)mp_get_int(&pKeyContext->rsa.e); + + return TRUE; +} + +BOOL import_private_key_impl(CONST BYTE *pbSrc, KEY_CONTEXT *pKeyContext, DWORD dwKeyLen, + DWORD dwPubExp) +{ + BYTE *pbTemp, *pbBigNum; + + if (mp_init_multi(&pKeyContext->rsa.e, &pKeyContext->rsa.d, &pKeyContext->rsa.N, + &pKeyContext->rsa.dQ,&pKeyContext->rsa.dP,&pKeyContext->rsa.qP, + &pKeyContext->rsa.p, &pKeyContext->rsa.q, NULL) != MP_OKAY) + { + SetLastError(NTE_FAIL); + return FALSE; + } + + pbTemp = HeapAlloc(GetProcessHeap(), 0, 2*dwKeyLen+5*((dwKeyLen+1)>>1)); + if (!pbTemp) return FALSE; + memcpy(pbTemp, pbSrc, 2*dwKeyLen+5*((dwKeyLen+1)>>1)); + pbBigNum = pbTemp; + + pKeyContext->rsa.type = PK_PRIVATE; + reverse_bytes(pbBigNum, dwKeyLen); + mp_read_unsigned_bin(&pKeyContext->rsa.N, pbBigNum, dwKeyLen); + pbBigNum += dwKeyLen; + reverse_bytes(pbBigNum, (dwKeyLen+1)>>1); + mp_read_unsigned_bin(&pKeyContext->rsa.p, pbBigNum, (dwKeyLen+1)>>1); + pbBigNum += (dwKeyLen+1)>>1; + reverse_bytes(pbBigNum, (dwKeyLen+1)>>1); + mp_read_unsigned_bin(&pKeyContext->rsa.q, pbBigNum, (dwKeyLen+1)>>1); + pbBigNum += (dwKeyLen+1)>>1; + reverse_bytes(pbBigNum, (dwKeyLen+1)>>1); + mp_read_unsigned_bin(&pKeyContext->rsa.dP, pbBigNum, (dwKeyLen+1)>>1); + pbBigNum += (dwKeyLen+1)>>1; + reverse_bytes(pbBigNum, (dwKeyLen+1)>>1); + mp_read_unsigned_bin(&pKeyContext->rsa.dQ, pbBigNum, (dwKeyLen+1)>>1); + pbBigNum += (dwKeyLen+1)>>1; + reverse_bytes(pbBigNum, (dwKeyLen+1)>>1); + mp_read_unsigned_bin(&pKeyContext->rsa.qP, pbBigNum, (dwKeyLen+1)>>1); + pbBigNum += (dwKeyLen+1)>>1; + reverse_bytes(pbBigNum, dwKeyLen); + mp_read_unsigned_bin(&pKeyContext->rsa.d, pbBigNum, dwKeyLen); + mp_set_int(&pKeyContext->rsa.e, dwPubExp); + + HeapFree(GetProcessHeap(), 0, pbTemp); + return TRUE; +} diff --git a/reactos/dll/win32/rsaenh/implglue.h b/reactos/dll/win32/rsaenh/implglue.h new file mode 100644 index 00000000000..d421c3d9ac8 --- /dev/null +++ b/reactos/dll/win32/rsaenh/implglue.h @@ -0,0 +1,100 @@ +/* + * dlls/rsaenh/implglue.h + * Glueing the RSAENH specific code to the crypto library + * + * Copyright (c) 2004 Michael Jung + * + * based on code by Mike McCormack and David Hammerton + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_IMPLGLUE_H +#define __WINE_IMPLGLUE_H + +#include "tomcrypt.h" + +/* Next typedef copied from dlls/advapi32/crypt_md4.c */ +typedef struct tagMD4_CTX { + unsigned int buf[4]; + unsigned int i[2]; + unsigned char in[64]; + unsigned char digest[16]; +} MD4_CTX; + +/* Next typedef copied from dlls/advapi32/crypt_md5.c */ +typedef struct tagMD5_CTX +{ + unsigned int i[2]; + unsigned int buf[4]; + unsigned char in[64]; + unsigned char digest[16]; +} MD5_CTX; + +/* Next typedef copied form dlls/advapi32/crypt_sha.c */ +typedef struct tagSHA_CTX +{ + ULONG Unknown[6]; + ULONG State[5]; + ULONG Count[2]; + UCHAR Buffer[64]; +} SHA_CTX, *PSHA_CTX; + +typedef union tagHASH_CONTEXT { + md2_state md2; + MD4_CTX md4; + MD5_CTX md5; + SHA_CTX sha; +} HASH_CONTEXT; + +typedef union tagKEY_CONTEXT { + rc2_key rc2; + des_key des; + des3_key des3; + prng_state rc4; + rsa_key rsa; +} KEY_CONTEXT; + +BOOL init_hash_impl(ALG_ID aiAlgid, HASH_CONTEXT *pHashContext); +BOOL update_hash_impl(ALG_ID aiAlgid, HASH_CONTEXT *pHashContext, CONST BYTE *pbData, + DWORD dwDataLen); +BOOL finalize_hash_impl(ALG_ID aiAlgid, HASH_CONTEXT *pHashContext, BYTE *pbHashValue); +BOOL duplicate_hash_impl(ALG_ID aiAlgid, CONST HASH_CONTEXT *pSrcHashContext, + HASH_CONTEXT *pDestHashContext); + +BOOL new_key_impl(ALG_ID aiAlgid, KEY_CONTEXT *pKeyContext, DWORD dwKeyLen); +BOOL free_key_impl(ALG_ID aiAlgid, KEY_CONTEXT *pKeyContext); +BOOL setup_key_impl(ALG_ID aiAlgid, KEY_CONTEXT *pKeyContext, DWORD dwKeyLen, + DWORD dwEffectiveKeyLen, DWORD dwSaltLen, BYTE *abKeyValue); +BOOL duplicate_key_impl(ALG_ID aiAlgid, CONST KEY_CONTEXT *pSrcKeyContext, + KEY_CONTEXT *pDestKeyContext); + +/* dwKeySpec is optional for symmetric key algorithms */ +BOOL encrypt_block_impl(ALG_ID aiAlgid, DWORD dwKeySpec, KEY_CONTEXT *pKeyContext, CONST BYTE *pbIn, BYTE *pbOut, + DWORD enc); +BOOL encrypt_stream_impl(ALG_ID aiAlgid, KEY_CONTEXT *pKeyContext, BYTE *pbInOut, DWORD dwLen); + +BOOL export_public_key_impl(BYTE *pbDest, const KEY_CONTEXT *pKeyContext, DWORD dwKeyLen, + DWORD *pdwPubExp); +BOOL import_public_key_impl(CONST BYTE *pbSrc, KEY_CONTEXT *pKeyContext, DWORD dwKeyLen, + DWORD dwPubExp); +BOOL export_private_key_impl(BYTE *pbDest, const KEY_CONTEXT *pKeyContext, DWORD dwKeyLen, + DWORD *pdwPubExp); +BOOL import_private_key_impl(CONST BYTE* pbSrc, KEY_CONTEXT *pKeyContext, DWORD dwKeyLen, + DWORD dwPubExp); + +BOOL gen_rand_impl(BYTE *pbBuffer, DWORD dwLen); + +#endif /* __WINE_IMPLGLUE_H */ diff --git a/reactos/dll/win32/rsaenh/md2.c b/reactos/dll/win32/rsaenh/md2.c new file mode 100644 index 00000000000..947a35985ee --- /dev/null +++ b/reactos/dll/win32/rsaenh/md2.c @@ -0,0 +1,151 @@ +/* + * dlls/rsaenh/md2.c + * MD2 (RFC 1319) hash function implementation by Tom St Denis + * + * Copyright 2004 Michael Jung + * Based on public domain code by Tom St Denis (tomstdenis@iahu.ca) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * This file contains code from the LibTomCrypt cryptographic + * library written by Tom St Denis (tomstdenis@iahu.ca). LibTomCrypt + * is in the public domain. The code in this file is tailored to + * special requirements. Take a look at http://libtomcrypt.org for the + * original version. + */ + +#include "tomcrypt.h" + +static const unsigned char PI_SUBST[256] = { + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, + 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, + 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, + 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, + 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, + 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, + 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, + 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, + 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, + 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, + 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, + 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, + 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, + 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, + 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, + 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, + 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 +}; + +/* adds 16 bytes to the checksum */ +static void md2_update_chksum(md2_state *md2) +{ + int j; + unsigned char L; + L = md2->chksum[15]; + for (j = 0; j < 16; j++) { + +/* caution, the RFC says its "C[j] = S[M[i*16+j] xor L]" but the reference source code [and test vectors] say + otherwise. +*/ + L = (md2->chksum[j] ^= PI_SUBST[(int)(md2->buf[j] ^ L)] & 255); + } +} + +static void md2_compress(md2_state *md2) +{ + int j, k; + unsigned char t; + + /* copy block */ + for (j = 0; j < 16; j++) { + md2->X[16+j] = md2->buf[j]; + md2->X[32+j] = md2->X[j] ^ md2->X[16+j]; + } + + t = (unsigned char)0; + + /* do 18 rounds */ + for (j = 0; j < 18; j++) { + for (k = 0; k < 48; k++) { + t = (md2->X[k] ^= PI_SUBST[(int)(t & 255)]); + } + t = (t + (unsigned char)j) & 255; + } +} + +int md2_init(md2_state *md2) +{ + /* MD2 uses a zero'ed state... */ + memset(md2->X, 0, sizeof(md2->X)); + memset(md2->chksum, 0, sizeof(md2->chksum)); + memset(md2->buf, 0, sizeof(md2->buf)); + md2->curlen = 0; + return CRYPT_OK; +} + +int md2_process(md2_state *md2, const unsigned char *buf, unsigned long len) +{ + unsigned long n; + + if (md2->curlen > sizeof(md2->buf)) { + return CRYPT_INVALID_ARG; + } + while (len > 0) { + n = MIN(len, (16 - md2->curlen)); + memcpy(md2->buf + md2->curlen, buf, (size_t)n); + md2->curlen += n; + buf += n; + len -= n; + + /* is 16 bytes full? */ + if (md2->curlen == 16) { + md2_compress(md2); + md2_update_chksum(md2); + md2->curlen = 0; + } + } + return CRYPT_OK; +} + +int md2_done(md2_state * md2, unsigned char *hash) +{ + unsigned long i, k; + + if (md2->curlen >= sizeof(md2->buf)) { + return CRYPT_INVALID_ARG; + } + + /* pad the message */ + k = 16 - md2->curlen; + for (i = md2->curlen; i < 16; i++) { + md2->buf[i] = (unsigned char)k; + } + + /* hash and update */ + md2_compress(md2); + md2_update_chksum(md2); + + /* hash checksum */ + memcpy(md2->buf, md2->chksum, 16); + md2_compress(md2); + + /* output is lower 16 bytes of X */ + memcpy(hash, md2->X, 16); + + return CRYPT_OK; +} diff --git a/reactos/dll/win32/rsaenh/mpi.c b/reactos/dll/win32/rsaenh/mpi.c new file mode 100644 index 00000000000..c6f083b6e2e --- /dev/null +++ b/reactos/dll/win32/rsaenh/mpi.c @@ -0,0 +1,4422 @@ +/* + * dlls/rsaenh/mpi.c + * Multi Precision Integer functions + * + * Copyright 2004 Michael Jung + * Based on public domain code by Tom St Denis (tomstdenis@iahu.ca) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * This file contains code from the LibTomCrypt cryptographic + * library written by Tom St Denis (tomstdenis@iahu.ca). LibTomCrypt + * is in the public domain. The code in this file is tailored to + * special requirements. Take a look at http://libtomcrypt.org for the + * original version. + */ + +#include +#include "tomcrypt.h" + +/* table of first PRIME_SIZE primes */ +static const mp_digit __prime_tab[]; + +/* Known optimal configurations + CPU /Compiler /MUL CUTOFF/SQR CUTOFF +------------------------------------------------------------- + Intel P4 Northwood /GCC v3.4.1 / 88/ 128/LTM 0.32 ;-) +*/ +static const int KARATSUBA_MUL_CUTOFF = 88, /* Min. number of digits before Karatsuba multiplication is used. */ + KARATSUBA_SQR_CUTOFF = 128; /* Min. number of digits before Karatsuba squaring is used. */ + +/* computes the modular inverse via binary extended euclidean algorithm, + * that is c = 1/a mod b + * + * Based on slow invmod except this is optimized for the case where b is + * odd as per HAC Note 14.64 on pp. 610 + */ +int +fast_mp_invmod (const mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, B, D; + int res, neg; + + /* 2. [modified] b must be odd */ + if (mp_iseven (b) == 1) { + return MP_VAL; + } + + /* init all our temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x == modulus, y == value to invert */ + if ((res = mp_copy (b, &x)) != MP_OKAY) { + goto __ERR; + } + + /* we need y = |a| */ + if ((res = mp_abs (a, &y)) != MP_OKAY) { + goto __ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto __ERR; + } + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto __ERR; + } + /* 4.2 if B is odd then */ + if (mp_isodd (&B) == 1) { + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto __ERR; + } + } + /* B = B/2 */ + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto __ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto __ERR; + } + /* 5.2 if D is odd then */ + if (mp_isodd (&D) == 1) { + /* D = (D-x)/2 */ + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto __ERR; + } + } + /* D = D/2 */ + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto __ERR; + } + } else { + /* v - v - u, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto __ERR; + } + + /* b is now the inverse */ + neg = a->sign; + while (D.sign == MP_NEG) { + if ((res = mp_add (&D, b, &D)) != MP_OKAY) { + goto __ERR; + } + } + mp_exch (&D, c); + c->sign = neg; + res = MP_OKAY; + +__ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL); + return res; +} + +/* computes xR**-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +int +fast_mp_montgomery_reduce (mp_int * x, const mp_int * n, mp_digit rho) +{ + int ix, res, olduse; + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < n->used + 1) { + if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { + return res; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + register mp_word *_W; + register mp_digit *tmpx; + + /* alias for the W[] array */ + _W = W; + + /* alias for the digits of x*/ + tmpx = x->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < x->used; ix++) { + *_W++ = *tmpx++; + } + + /* zero the high words of W[a->used..m->used*2] */ + for (; ix < n->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + /* now we proceed to zero successive digits + * from the least significant upwards + */ + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires + * that W[ix-1] have the carry cleared (see after the inner loop) + */ + register mp_digit mu; + mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK); + + /* a = a + mu * m * b**i + * + * This is computed in place and on the fly. The multiplication + * by b**i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the + * inner loop In this case we fix the carry from the previous + * column since the Montgomery reduction requires digits of the + * result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The + * carry fixups are done in order so after these loops the + * first m->used words of W[] have the carries fixed + */ + { + register int iy; + register mp_digit *tmpn; + register mp_word *_W; + + /* alias for the digits of the modulus */ + tmpn = n->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < n->used; iy++) { + *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++); + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + register mp_digit *tmpx; + register mp_word *_W, *_W1; + + /* nox fix rest of carries */ + + /* alias for current word */ + _W1 = W + ix; + + /* alias for next word, where the carry goes */ + _W = W + ++ix; + + for (; ix <= n->used * 2 + 1; ix++) { + *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); + } + + /* copy out, A = A/b**n + * + * The result is A/b**n but instead of converting from an + * array of mp_word to mp_digit than calling mp_rshd + * we just copy them in the right order + */ + + /* alias for destination word */ + tmpx = x->dp; + + /* alias for shifted double precision result */ + _W = W + n->used; + + for (ix = 0; ix < n->used + 1; ix++) { + *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK)); + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits + */ + for (; ix < olduse; ix++) { + *tmpx++ = 0; + } + } + + /* set the max used and clamp */ + x->used = n->used + 1; + mp_clamp (x); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + return MP_OKAY; +} + +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). + * + * Based on Algorithm 14.12 on pp.595 of HAC. + * + */ +int +fast_s_mp_mul_digs (const mp_int * a, const mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + register mp_word _W; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = MIN(digs, a->used + b->used); + + /* clear the carry */ + _W = 0; + for (ix = 0; ix <= pa; ix++) { + int tx, ty; + int iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially its + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; ++iz) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + } + + /* store term */ + W[ix] = ((mp_digit)_W) & MP_MASK; + + /* make next carry */ + _W = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = digs; + + { + register mp_digit *tmpc; + tmpc = c->dp; + for (ix = 0; ix < digs; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} + +/* this is a modified version of fast_s_mul_digs that only produces + * output digits *above* digs. See the comments for fast_s_mul_digs + * to see how it works. + * + * This is used in the Barrett reduction since for one of the multiplications + * only the higher digits were needed. This essentially halves the work. + * + * Based on Algorithm 14.12 on pp.595 of HAC. + */ +int +fast_s_mp_mul_high_digs (const mp_int * a, const mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + mp_word _W; + + /* grow the destination as required */ + pa = a->used + b->used; + if (c->alloc < pa) { + if ((res = mp_grow (c, pa)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = a->used + b->used; + _W = 0; + for (ix = digs; ix <= pa; ix++) { + int tx, ty, iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially its + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + } + + /* store term */ + W[ix] = ((mp_digit)_W) & MP_MASK; + + /* make next carry */ + _W = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + register mp_digit *tmpc; + + tmpc = c->dp + digs; + for (ix = digs; ix <= pa; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} + +/* fast squaring + * + * This is the comba method where the columns of the product + * are computed first then the carries are computed. This + * has the effect of making a very simple inner loop that + * is executed the most + * + * W2 represents the outer products and W the inner. + * + * A further optimizations is made because the inner + * products are of the form "A * B * 2". The *2 part does + * not need to be computed until the end which is good + * because 64-bit shifts are slow! + * + * Based on Algorithm 14.16 on pp.597 of HAC. + * + */ +/* the jist of squaring... + +you do like mult except the offset of the tmpx [one that starts closer to zero] +can't equal the offset of tmpy. So basically you set up iy like before then you min it with +(ty-tx) so that it never happens. You double all those you add in the inner loop + +After that loop you do the squares and add them in. + +Remove W2 and don't memset W + +*/ + +int fast_s_mp_sqr (const mp_int * a, mp_int * b) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY], *tmpx; + mp_word W1; + + /* grow the destination as required */ + pa = a->used + a->used; + if (b->alloc < pa) { + if ((res = mp_grow (b, pa)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + W1 = 0; + for (ix = 0; ix <= pa; ix++) { + int tx, ty, iy; + mp_word _W; + mp_digit *tmpy; + + /* clear counter */ + _W = 0; + + /* get offsets into the two bignums */ + ty = MIN(a->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = a->dp + ty; + + /* this is the number of times the loop will iterrate, essentially its + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* now for squaring tx can never equal ty + * we halve the distance since they approach at a rate of 2x + * and we have to round because odd cases need to be executed + */ + iy = MIN(iy, (ty-tx+1)>>1); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + } + + /* double the inner product and add carry */ + _W = _W + _W + W1; + + /* even columns have the square term in them */ + if ((ix&1) == 0) { + _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]); + } + + /* store it */ + W[ix] = _W; + + /* make next carry */ + W1 = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = b->used; + b->used = a->used+a->used; + + { + mp_digit *tmpb; + tmpb = b->dp; + for (ix = 0; ix < pa; ix++) { + *tmpb++ = W[ix] & MP_MASK; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + mp_clamp (b); + return MP_OKAY; +} + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +int +mp_2expt (mp_int * a, int b) +{ + int res; + + /* zero a as per default */ + mp_zero (a); + + /* grow a to accommodate the single bit */ + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + + /* set the used count of where the bit will go */ + a->used = b / DIGIT_BIT + 1; + + /* put the single bit in its place */ + a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); + + return MP_OKAY; +} + +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +int +mp_abs (const mp_int * a, mp_int * b) +{ + int res; + + /* copy a to b */ + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} + +/* high level addition (handles signs) */ +int mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag (a, b) == MP_LT) { + c->sign = sb; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + + +/* single digit addition */ +int +mp_add_d (mp_int * a, mp_digit b, mp_int * c) +{ + int res, ix, oldused; + mp_digit *tmpa, *tmpc, mu; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative and |a| >= b, call c = |a| - b */ + if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) { + /* temporarily fix sign of a */ + a->sign = MP_ZPOS; + + /* c = |a| - b */ + res = mp_sub_d(a, b, c); + + /* fix sign */ + a->sign = c->sign = MP_NEG; + + return res; + } + + /* old number of used digits in c */ + oldused = c->used; + + /* sign always positive */ + c->sign = MP_ZPOS; + + /* source alias */ + tmpa = a->dp; + + /* destination alias */ + tmpc = c->dp; + + /* if a is positive */ + if (a->sign == MP_ZPOS) { + /* add digit, after this we're propagating + * the carry. + */ + *tmpc = *tmpa++ + b; + mu = *tmpc >> DIGIT_BIT; + *tmpc++ &= MP_MASK; + + /* now handle rest of the digits */ + for (ix = 1; ix < a->used; ix++) { + *tmpc = *tmpa++ + mu; + mu = *tmpc >> DIGIT_BIT; + *tmpc++ &= MP_MASK; + } + /* set final carry */ + ix++; + *tmpc++ = mu; + + /* setup size */ + c->used = a->used + 1; + } else { + /* a was negative and |a| < b */ + c->used = 1; + + /* the result is a single digit */ + if (a->used == 1) { + *tmpc++ = b - a->dp[0]; + } else { + *tmpc++ = b; + } + + /* setup count so the clearing of oldused + * can fall through correctly + */ + ix = 1; + } + + /* now zero to oldused */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + + return MP_OKAY; +} + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +void +mp_clamp (mp_int * a) +{ + /* decrease used while the most significant digit is + * zero. + */ + while (a->used > 0 && a->dp[a->used - 1] == 0) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} + +/* clear one (frees) */ +void +mp_clear (mp_int * a) +{ + int i; + + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* first zero the digits */ + for (i = 0; i < a->used; i++) { + a->dp[i] = 0; + } + + /* free ram */ + free(a->dp); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} + + +void mp_clear_multi(mp_int *mp, ...) +{ + mp_int* next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int*); + } + va_end(args); +} + +/* compare two ints (signed)*/ +int +mp_cmp (const mp_int * a, const mp_int * b) +{ + /* compare based on sign */ + if (a->sign != b->sign) { + if (a->sign == MP_NEG) { + return MP_LT; + } else { + return MP_GT; + } + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} + +/* compare a digit */ +int mp_cmp_d(const mp_int * a, mp_digit b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG) { + return MP_LT; + } + + /* compare based on magnitude */ + if (a->used > 1) { + return MP_GT; + } + + /* compare the only digit of a to b */ + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} + +/* compare maginitude of two ints (unsigned) */ +int mp_cmp_mag (const mp_int * a, const mp_int * b) +{ + int n; + mp_digit *tmpa, *tmpb; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* alias for a */ + tmpa = a->dp + (a->used - 1); + + /* alias for b */ + tmpb = b->dp + (a->used - 1); + + /* compare based on digits */ + for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { + if (*tmpa > *tmpb) { + return MP_GT; + } + + if (*tmpa < *tmpb) { + return MP_LT; + } + } + return MP_EQ; +} + +static const int lnz[16] = { + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +/* Counts the number of lsbs which are zero before the first zero bit */ +int mp_cnt_lsb(const mp_int *a) +{ + int x; + mp_digit q, qq; + + /* easy out */ + if (mp_iszero(a) == 1) { + return 0; + } + + /* scan lower digits until non-zero */ + for (x = 0; x < a->used && a->dp[x] == 0; x++); + q = a->dp[x]; + x *= DIGIT_BIT; + + /* now scan this digit until a 1 is found */ + if ((q & 1) == 0) { + do { + qq = q & 15; + x += lnz[qq]; + q >>= 4; + } while (qq == 0); + } + return x; +} + +/* copy, b = a */ +int +mp_copy (const mp_int * a, mp_int * b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + /* zero b and copy the parameters over */ + { + register mp_digit *tmpa, *tmpb; + + /* pointer aliases */ + + /* source */ + tmpa = a->dp; + + /* destination */ + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} + +/* returns the number of bits in an int */ +int +mp_count_bits (const mp_int * a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (a->used == 0) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} + +/* integer signed division. + * c*b + d == a [e.g. a/b, c=quotient, d=remainder] + * HAC pp.598 Algorithm 14.20 + * + * Note that the description in HAC is horribly + * incomplete. For example, it doesn't consider + * the case where digits are removed from 'x' in + * the inner loop. It also doesn't consider the + * case that y has fewer than three digits, etc.. + * + * The overall algorithm is as described as + * 14.20 from HAC but fixed to treat these cases. +*/ +int mp_div (const mp_int * a, const mp_int * b, mp_int * c, mp_int * d) +{ + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; + + if ((res = mp_init (&t1)) != MP_OKAY) { + goto __Q; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto __T1; + } + + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto __T2; + } + + if ((res = mp_init_copy (&y, b)) != MP_OKAY) { + goto __X; + } + + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ + norm = mp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { + goto __Y; + } + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ + goto __Y; + } + + while (mp_cmp (&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { + goto __Y; + } + } + + /* reset y by shifting it back down */ + mp_rshd (&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) { + continue; + } + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, + * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); + } else { + mp_word tmp; + tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); + tmp |= ((mp_word) x.dp[i - 1]); + tmp /= ((mp_word) y.dp[t]); + if (tmp > (mp_word) MP_MASK) + tmp = MP_MASK; + q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); + } + + /* while (q{i-t-1} * (yt * b + y{t-1})) > + xi * b**2 + xi-1 * b + xi-2 + + do q{i-t-1} -= 1; + */ + q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; + + /* find left hand */ + mp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto __Y; + } + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ + if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto __Y; + } + + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto __Y; + } + + if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { + goto __Y; + } + + /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == MP_NEG) { + if ((res = mp_copy (&y, &t1)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { + goto __Y; + } + + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; + } + } + + /* now q is the quotient and x is the remainder + * [which we have to normalize] + */ + + /* get sign before writing to c */ + x.sign = x.used == 0 ? MP_ZPOS : a->sign; + + if (c != NULL) { + mp_clamp (&q); + mp_exch (&q, c); + c->sign = neg; + } + + if (d != NULL) { + mp_div_2d (&x, norm, &x, NULL); + mp_exch (&x, d); + } + + res = MP_OKAY; + +__Y:mp_clear (&y); +__X:mp_clear (&x); +__T2:mp_clear (&t2); +__T1:mp_clear (&t1); +__Q:mp_clear (&q); + return res; +} + +/* b = a/2 */ +int mp_div_2(const mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + mp_clamp (b); + return MP_OKAY; +} + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +int mp_div_2d (const mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + register mp_digit *tmpc, mask, shift; + + /* mask */ + mask = (((mp_digit)1) << D) - 1; + + /* shift for lsb */ + shift = DIGIT_BIT - D; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from the previous word */ + *tmpc = (*tmpc >> D) | (r << shift); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } + } + mp_clamp (c); + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} + +static int s_is_power_of_two(mp_digit b, int *p) +{ + int x; + + for (x = 1; x < DIGIT_BIT; x++) { + if (b == (((mp_digit)1)<dp[0] & ((((mp_digit)1)<used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= b) { + t = (mp_digit)(w / b); + w -= ((mp_word)t) * ((mp_word)b); + } else { + t = 0; + } + q.dp[ix] = (mp_digit)t; + } + + if (d != NULL) { + *d = (mp_digit)w; + } + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + +/* reduce "x" in place modulo "n" using the Diminished Radix algorithm. + * + * Based on algorithm from the paper + * + * "Generating Efficient Primes for Discrete Log Cryptosystems" + * Chae Hoon Lim, Pil Loong Lee, + * POSTECH Information Research Laboratories + * + * The modulus must be of a special format [see manual] + * + * Has been modified to use algorithm 7.10 from the LTM book instead + * + * Input x must be in the range 0 <= x <= (n-1)**2 + */ +int +mp_dr_reduce (mp_int * x, const mp_int * n, mp_digit k) +{ + int err, i, m; + mp_word r; + mp_digit mu, *tmpx1, *tmpx2; + + /* m = digits in modulus */ + m = n->used; + + /* ensure that "x" has at least 2m digits */ + if (x->alloc < m + m) { + if ((err = mp_grow (x, m + m)) != MP_OKAY) { + return err; + } + } + +/* top of loop, this is where the code resumes if + * another reduction pass is required. + */ +top: + /* aliases for digits */ + /* alias for lower half of x */ + tmpx1 = x->dp; + + /* alias for upper half of x, or x/B**m */ + tmpx2 = x->dp + m; + + /* set carry to zero */ + mu = 0; + + /* compute (x mod B**m) + k * [x/B**m] inline and inplace */ + for (i = 0; i < m; i++) { + r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu; + *tmpx1++ = (mp_digit)(r & MP_MASK); + mu = (mp_digit)(r >> ((mp_word)DIGIT_BIT)); + } + + /* set final carry */ + *tmpx1++ = mu; + + /* zero words above m */ + for (i = m + 1; i < x->used; i++) { + *tmpx1++ = 0; + } + + /* clamp, sub and return */ + mp_clamp (x); + + /* if x >= n then subtract and reduce again + * Each successive "recursion" makes the input smaller and smaller. + */ + if (mp_cmp_mag (x, n) != MP_LT) { + s_mp_sub(x, n, x); + goto top; + } + return MP_OKAY; +} + +/* determines the setup value */ +void mp_dr_setup(const mp_int *a, mp_digit *d) +{ + /* the casts are required if DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] + */ + *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - + ((mp_word)a->dp[0])); +} + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +void +mp_exch (mp_int * a, mp_int * b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted a lot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +int mp_exptmod (const mp_int * G, const mp_int * X, mp_int * P, mp_int * Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + dr = 0; + + /* if the modulus is odd or dr != 0 use the fast method */ + if (mp_isodd (P) == 1 || dr != 0) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { + /* otherwise use the generic Barrett reduction technique */ + return s_mp_exptmod (G, X, P, Y); + } +} + +/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ + +int +mp_exptmod_fast (const mp_int * G, const mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[256], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* use a pointer to the reduction algorithm. This allows us to use + * one of many reduction algorithms without modding the guts of + * the code with if statements everywhere. + */ + int (*redux)(mp_int*,const mp_int*,mp_digit); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto __M; + } + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ + if (((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else { + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; + } + } else if (redmode == 1) { + /* setup DR reduction for moduli of the form B**k - b */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; + } else { + /* setup DR reduction for moduli of the form 2**k - b */ + if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { + goto __M; + } + redux = mp_reduce_2k; + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto __M; + } + + /* create M table + * + + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { + goto __RES; + } + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { + goto __RES; + } + } else { + mp_set(&res, 1); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { + goto __RES; + } + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&M[x], P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits so break */ + if (digidx == -1) { + break; + } + /* read next digit and reset bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + + /* get next bit of the window */ + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + } + } + + if (redmode == 0) { + /* fixup result if Montgomery reduction is used + * recall that any value in a Montgomery system is + * actually multiplied by R mod n. So we have + * to reduce one more time to cancel out the factor + * of R. + */ + if ((err = redux(&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* swap res with Y */ + mp_exch (&res, Y); + err = MP_OKAY; +__RES:mp_clear (&res); +__M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + +/* Greatest Common Divisor using the binary method */ +int mp_gcd (const mp_int * a, const mp_int * b, mp_int * c) +{ + mp_int u, v; + int k, u_lsb, v_lsb, res; + + /* either zero than gcd is the largest */ + if (mp_iszero (a) == 1 && mp_iszero (b) == 0) { + return mp_abs (b, c); + } + if (mp_iszero (a) == 0 && mp_iszero (b) == 1) { + return mp_abs (a, c); + } + + /* optimized. At this point if a == 0 then + * b must equal zero too + */ + if (mp_iszero (a) == 1) { + mp_zero(c); + return MP_OKAY; + } + + /* get copies of a and b we can modify */ + if ((res = mp_init_copy (&u, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init_copy (&v, b)) != MP_OKAY) { + goto __U; + } + + /* must be positive for the remainder of the algorithm */ + u.sign = v.sign = MP_ZPOS; + + /* B1. Find the common power of two for u and v */ + u_lsb = mp_cnt_lsb(&u); + v_lsb = mp_cnt_lsb(&v); + k = MIN(u_lsb, v_lsb); + + if (k > 0) { + /* divide the power of two out */ + if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) { + goto __V; + } + + if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) { + goto __V; + } + } + + /* divide any remaining factors of two out */ + if (u_lsb != k) { + if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) { + goto __V; + } + } + + if (v_lsb != k) { + if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) { + goto __V; + } + } + + while (mp_iszero(&v) == 0) { + /* make sure v is the largest */ + if (mp_cmp_mag(&u, &v) == MP_GT) { + /* swap u and v to make sure v is >= u */ + mp_exch(&u, &v); + } + + /* subtract smallest from largest */ + if ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) { + goto __V; + } + + /* Divide out all factors of two */ + if ((res = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) { + goto __V; + } + } + + /* multiply by 2**k which we divided out at the beginning */ + if ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) { + goto __V; + } + c->sign = MP_ZPOS; + res = MP_OKAY; +__V:mp_clear (&u); +__U:mp_clear (&v); + return res; +} + +/* get the lower 32-bits of an mp_int */ +unsigned long mp_get_int(const mp_int * a) +{ + int i; + unsigned long res; + + if (a->used == 0) { + return 0; + } + + /* get number of digits of the lsb we have to read */ + i = MIN(a->used,(int)((sizeof(unsigned long)*CHAR_BIT+DIGIT_BIT-1)/DIGIT_BIT))-1; + + /* get most significant digit of result */ + res = DIGIT(a,i); + + while (--i >= 0) { + res = (res << DIGIT_BIT) | DIGIT(a,i); + } + + /* force result to 32-bits always so it is consistent on non 32-bit platforms */ + return res & 0xFFFFFFFFUL; +} + +/* grow as required */ +int mp_grow (mp_int * a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* reallocate the array a->dp + * + * We store the return in a temporary variable + * in case the operation failed we don't want + * to overwrite the dp member of a. + */ + tmp = realloc (a->dp, sizeof (mp_digit) * size); + if (tmp == NULL) { + /* reallocation failed but "a" is still valid [can be freed] */ + return MP_MEM; + } + + /* reallocation succeeded so set a->dp */ + a->dp = tmp; + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} + +/* init a new mp_int */ +int mp_init (mp_int * a) +{ + int i; + + /* allocate memory required and clear it */ + a->dp = malloc (sizeof (mp_digit) * MP_PREC); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the digits to zero */ + for (i = 0; i < MP_PREC; i++) { + a->dp[i] = 0; + } + + /* set the used to zero, allocated digits to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + +/* creates "a" then copies b into it */ +int mp_init_copy (mp_int * a, const mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} + +int mp_init_multi(mp_int *mp, ...) +{ + mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int* cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} + +/* init an mp_init for a given size */ +int mp_init_size (mp_int * a, int size) +{ + int x; + + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* alloc mem */ + a->dp = malloc (sizeof (mp_digit) * size); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the members */ + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + /* zero the digits */ + for (x = 0; x < size; x++) { + a->dp[x] = 0; + } + + return MP_OKAY; +} + +/* hac 14.61, pp608 */ +int mp_invmod (const mp_int * a, mp_int * b, mp_int * c) +{ + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + + /* if the modulus is odd we can use a faster routine instead */ + if (mp_isodd (b) == 1) { + return fast_mp_invmod (a, b, c); + } + + return mp_invmod_slow(a, b, c); +} + +/* hac 14.61, pp608 */ +int mp_invmod_slow (const mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_copy (a, &x)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto __ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto __ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto __ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto __ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto __ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto __ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto __ERR; + } + /* 5.2 if C or D is odd then */ + if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto __ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto __ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto __ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0) == MP_LT) { + if ((res = mp_add(&C, b, &C)) != MP_OKAY) { + goto __ERR; + } + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { + goto __ERR; + } + } + + /* C is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; +__ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return res; +} + +/* c = |a| * |b| using Karatsuba Multiplication using + * three half size multiplications + * + * Let B represent the radix [e.g. 2**DIGIT_BIT] and + * let n represent half of the number of digits in + * the min(a,b) + * + * a = a1 * B**n + a0 + * b = b1 * B**n + b0 + * + * Then, a * b => + a1b1 * B**2n + ((a1 - a0)(b1 - b0) + a0b0 + a1b1) * B + a0b0 + * + * Note that a1b1 and a0b0 are used twice and only need to be + * computed once. So in total three half size (half # of + * digit) multiplications are performed, a0b0, a1b1 and + * (a1-b1)(a0-b0) + * + * Note that a multiplication of half the digits requires + * 1/4th the number of single precision multiplications so in + * total after one call 25% of the single precision multiplications + * are saved. Note also that the call to mp_mul can end up back + * in this function if the a0, a1, b0, or b1 are above the threshold. + * This is known as divide-and-conquer and leads to the famous + * O(N**lg(3)) or O(N**1.584) work which is asymptopically lower than + * the standard O(N**2) that the baseline/comba methods use. + * Generally though the overhead of this method doesn't pay off + * until a certain size (N ~ 80) is reached. + */ +int mp_karatsuba_mul (const mp_int * a, const mp_int * b, mp_int * c) +{ + mp_int x0, x1, y0, y1, t1, x0y0, x1y1; + int B, err; + + /* default the return code to an error */ + err = MP_MEM; + + /* min # of digits */ + B = MIN (a->used, b->used); + + /* now divide in two */ + B = B >> 1; + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto ERR; + if (mp_init_size (&x1, a->used - B) != MP_OKAY) + goto X0; + if (mp_init_size (&y0, B) != MP_OKAY) + goto X1; + if (mp_init_size (&y1, b->used - B) != MP_OKAY) + goto Y0; + + /* init temps */ + if (mp_init_size (&t1, B * 2) != MP_OKAY) + goto Y1; + if (mp_init_size (&x0y0, B * 2) != MP_OKAY) + goto T1; + if (mp_init_size (&x1y1, B * 2) != MP_OKAY) + goto X0Y0; + + /* now shift the digits */ + x0.used = y0.used = B; + x1.used = a->used - B; + y1.used = b->used - B; + + { + register int x; + register mp_digit *tmpa, *tmpb, *tmpx, *tmpy; + + /* we copy the digits directly instead of using higher level functions + * since we also need to shift the digits + */ + tmpa = a->dp; + tmpb = b->dp; + + tmpx = x0.dp; + tmpy = y0.dp; + for (x = 0; x < B; x++) { + *tmpx++ = *tmpa++; + *tmpy++ = *tmpb++; + } + + tmpx = x1.dp; + for (x = B; x < a->used; x++) { + *tmpx++ = *tmpa++; + } + + tmpy = y1.dp; + for (x = B; x < b->used; x++) { + *tmpy++ = *tmpb++; + } + } + + /* only need to clamp the lower words since by definition the + * upper words x1/y1 must have a known number of digits + */ + mp_clamp (&x0); + mp_clamp (&y0); + + /* now calc the products x0y0 and x1y1 */ + /* after this x0 is no longer required, free temp [x0==t2]! */ + if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY) + goto X1Y1; /* x0y0 = x0*y0 */ + if (mp_mul (&x1, &y1, &x1y1) != MP_OKAY) + goto X1Y1; /* x1y1 = x1*y1 */ + + /* now calc x1-x0 and y1-y0 */ + if (mp_sub (&x1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x1 - x0 */ + if (mp_sub (&y1, &y0, &x0) != MP_OKAY) + goto X1Y1; /* t2 = y1 - y0 */ + if (mp_mul (&t1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = (x1 - x0) * (y1 - y0) */ + + /* add x0y0 */ + if (mp_add (&x0y0, &x1y1, &x0) != MP_OKAY) + goto X1Y1; /* t2 = x0y0 + x1y1 */ + if (mp_sub (&x0, &t1, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ + + /* shift by B */ + if (mp_lshd (&t1, B) != MP_OKAY) + goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<used; + + /* now divide in two */ + B = B >> 1; + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto ERR; + if (mp_init_size (&x1, a->used - B) != MP_OKAY) + goto X0; + + /* init temps */ + if (mp_init_size (&t1, a->used * 2) != MP_OKAY) + goto X1; + if (mp_init_size (&t2, a->used * 2) != MP_OKAY) + goto T1; + if (mp_init_size (&x0x0, B * 2) != MP_OKAY) + goto T2; + if (mp_init_size (&x1x1, (a->used - B) * 2) != MP_OKAY) + goto X0X0; + + { + register int x; + register mp_digit *dst, *src; + + src = a->dp; + + /* now shift the digits */ + dst = x0.dp; + for (x = 0; x < B; x++) { + *dst++ = *src++; + } + + dst = x1.dp; + for (x = B; x < a->used; x++) { + *dst++ = *src++; + } + } + + x0.used = B; + x1.used = a->used - B; + + mp_clamp (&x0); + + /* now calc the products x0*x0 and x1*x1 */ + if (mp_sqr (&x0, &x0x0) != MP_OKAY) + goto X1X1; /* x0x0 = x0*x0 */ + if (mp_sqr (&x1, &x1x1) != MP_OKAY) + goto X1X1; /* x1x1 = x1*x1 */ + + /* now calc (x1-x0)**2 */ + if (mp_sub (&x1, &x0, &t1) != MP_OKAY) + goto X1X1; /* t1 = x1 - x0 */ + if (mp_sqr (&t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */ + + /* add x0y0 */ + if (s_mp_add (&x0x0, &x1x1, &t2) != MP_OKAY) + goto X1X1; /* t2 = x0x0 + x1x1 */ + if (mp_sub (&t2, &t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = x0x0 + x1x1 - (x1-x0)*(x1-x0) */ + + /* shift by B */ + if (mp_lshd (&t1, B) != MP_OKAY) + goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))<sign = MP_ZPOS; + +__T: + mp_clear_multi (&t1, &t2, NULL); + return res; +} + +/* shift left a certain amount of digits */ +int mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + register mp_digit *top, *bottom; + + /* increment the used by the shift amount then copy upwards */ + a->used += b; + + /* top */ + top = a->dp + a->used - 1; + + /* base */ + bottom = a->dp + a->used - 1 - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *top-- = *bottom--; + } + + /* zero the lower digits */ + top = a->dp; + for (x = 0; x < b; x++) { + *top++ = 0; + } + } + return MP_OKAY; +} + +/* c = a mod b, 0 <= c < b */ +int +mp_mod (const mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign != b->sign) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} + +/* calc a value mod 2**b */ +int +mp_mod_2d (const mp_int * a, int b, mp_int * c) +{ + int x, res; + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero (c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b > (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= + (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} + +int +mp_mod_d (const mp_int * a, mp_digit b, mp_digit * c) +{ + return mp_div_d(a, b, NULL, c); +} + +/* + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally up to just under + * the leading bit of b. This saves a lot of multiple precision shifting. + */ +int mp_montgomery_calc_normalization (mp_int * a, const mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + + if (b->used > 1) { + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + } else { + mp_set(a, 1); + bits = 1; + } + + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} + +/* computes xR**-1 == x (mod N) via Montgomery Reduction */ +int +mp_montgomery_reduce (mp_int * x, const mp_int * n, mp_digit rho) +{ + int ix, res, digs; + mp_digit mu; + + /* can the fast reduction [comba] method be used? + * + * Note that unlike in mul you're safely allowed *less* + * than the available columns [255 per default] since carries + * are fixed up in the inner loop. + */ + digs = n->used * 2 + 1; + if ((digs < MP_WARRAY) && + n->used < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_mp_montgomery_reduce (x, n, rho); + } + + /* grow the input as required */ + if (x->alloc < digs) { + if ((res = mp_grow (x, digs)) != MP_OKAY) { + return res; + } + } + x->used = digs; + + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * rho mod b + * + * The value of rho must be precalculated via + * montgomery_setup() such that + * it equals -1/n0 mod b this allows the + * following inner loop to reduce the + * input one digit at a time + */ + mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK); + + /* a = a + mu * m * b**i */ + { + register int iy; + register mp_digit *tmpn, *tmpx, u; + register mp_word r; + + /* alias for digits of the modulus */ + tmpn = n->dp; + + /* alias for the digits of x [the input] */ + tmpx = x->dp + ix; + + /* set the carry to zero */ + u = 0; + + /* Multiply and add in place */ + for (iy = 0; iy < n->used; iy++) { + /* compute product and sum */ + r = ((mp_word)mu) * ((mp_word)*tmpn++) + + ((mp_word) u) + ((mp_word) * tmpx); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* fix digit */ + *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK)); + } + /* At this point the ix'th digit of x should be zero */ + + + /* propagate carries upwards as required*/ + while (u) { + *tmpx += u; + u = *tmpx >> DIGIT_BIT; + *tmpx++ &= MP_MASK; + } + } + } + + /* at this point the n.used'th least + * significant digits of x are all zero + * which means we can shift x to the + * right by n.used digits and the + * residue is unchanged. + */ + + /* x = x/b**n.used */ + mp_clamp(x); + mp_rshd (x, n->used); + + /* if x >= n then x = x - n */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + + return MP_OKAY; +} + +/* setups the montgomery reduction stuff */ +int +mp_montgomery_setup (const mp_int * n, mp_digit * rho) +{ + mp_digit x, b; + +/* fast inversion mod 2**k + * + * Based on the fact that + * + * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = n->dp[0]; + + if ((b & 1) == 0) { + return MP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2 - b * x; /* here x*a==1 mod 2**8 */ + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ + + /* rho = -1/m mod b */ + *rho = (((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} + +/* high level multiplication (handles sign) */ +int mp_mul (const mp_int * a, const mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + /* use Karatsuba? */ + if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul (a, b, c); + } else + { + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will + * have less than MP_WARRAY digits and the number of + * digits won't affect carry propagation + */ + int digs = a->used + b->used + 1; + + if ((digs < MP_WARRAY) && + MIN(a->used, b->used) <= + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else + res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ + } + c->sign = (c->used > 0) ? neg : MP_ZPOS; + return res; +} + +/* b = a*2 */ +int mp_mul_2(const mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accommodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++(b->used); + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + return MP_OKAY; +} + +/* shift left by a certain bit count */ +int mp_mul_2d (const mp_int * a, int b, mp_int * c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + register mp_digit *tmpc, shift, mask, r, rr; + register int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* shift for msbs */ + shift = DIGIT_BIT - d; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> shift) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + + /* set final carry */ + if (r != 0) { + c->dp[(c->used)++] = r; + } + } + mp_clamp (c); + return MP_OKAY; +} + +/* multiply by a digit */ +int +mp_mul_d (const mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + int ix, res, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the sign */ + c->sign = a->sign; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + + /* compute columns */ + for (ix = 0; ix < a->used; ix++) { + /* compute product and carry sum for this term */ + r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* send carry into next iteration */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + + /* store final carry [if any] */ + *tmpc++ = u; + + /* now zero digits above the top */ + while (ix++ < olduse) { + *tmpc++ = 0; + } + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} + +/* d = a * b (mod c) */ +int +mp_mulmod (const mp_int * a, const mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/* determines if an integers is divisible by one + * of the first PRIME_SIZE primes or not + * + * sets result to 0 if not, 1 if yes + */ +int mp_prime_is_divisible (const mp_int * a, int *result) +{ + int err, ix; + mp_digit res; + + /* default to not */ + *result = MP_NO; + + for (ix = 0; ix < PRIME_SIZE; ix++) { + /* what is a mod __prime_tab[ix] */ + if ((err = mp_mod_d (a, __prime_tab[ix], &res)) != MP_OKAY) { + return err; + } + + /* is the residue zero? */ + if (res == 0) { + *result = MP_YES; + return MP_OKAY; + } + } + + return MP_OKAY; +} + +/* performs a variable number of rounds of Miller-Rabin + * + * Probability of error after t rounds is no more than + + * + * Sets result to 1 if probably prime, 0 otherwise + */ +int mp_prime_is_prime (mp_int * a, int t, int *result) +{ + mp_int b; + int ix, err, res; + + /* default to no */ + *result = MP_NO; + + /* valid value of t? */ + if (t <= 0 || t > PRIME_SIZE) { + return MP_VAL; + } + + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < PRIME_SIZE; ix++) { + if (mp_cmp_d(a, __prime_tab[ix]) == MP_EQ) { + *result = 1; + return MP_OKAY; + } + } + + /* first perform trial division */ + if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { + return err; + } + + /* return if it was trivially divisible */ + if (res == MP_YES) { + return MP_OKAY; + } + + /* now perform the miller-rabin rounds */ + if ((err = mp_init (&b)) != MP_OKAY) { + return err; + } + + for (ix = 0; ix < t; ix++) { + /* set the prime */ + mp_set (&b, __prime_tab[ix]); + + if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) { + goto __B; + } + + if (res == MP_NO) { + goto __B; + } + } + + /* passed the test */ + *result = MP_YES; +__B:mp_clear (&b); + return err; +} + +/* Miller-Rabin test of "a" to the base of "b" as described in + * HAC pp. 139 Algorithm 4.24 + * + * Sets result to 0 if definitely composite or 1 if probably prime. + * Randomly the chance of error is no more than 1/4 and often + * very much lower. + */ +int mp_prime_miller_rabin (mp_int * a, const mp_int * b, int *result) +{ + mp_int n1, y, r; + int s, j, err; + + /* default */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1) != MP_GT) { + return MP_VAL; + } + + /* get n1 = a - 1 */ + if ((err = mp_init_copy (&n1, a)) != MP_OKAY) { + return err; + } + if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) { + goto __N1; + } + + /* set 2**s * r = n1 */ + if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) { + goto __N1; + } + + /* count the number of least significant bits + * which are zero + */ + s = mp_cnt_lsb(&r); + + /* now divide n - 1 by 2**s */ + if ((err = mp_div_2d (&r, s, &r, NULL)) != MP_OKAY) { + goto __R; + } + + /* compute y = b**r mod a */ + if ((err = mp_init (&y)) != MP_OKAY) { + goto __R; + } + if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) { + goto __Y; + } + + /* if y != 1 and y != n1 do */ + if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) { + j = 1; + /* while j <= s-1 and y != n1 */ + while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) { + if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) { + goto __Y; + } + + /* if y == 1 then composite */ + if (mp_cmp_d (&y, 1) == MP_EQ) { + goto __Y; + } + + ++j; + } + + /* if y != n1 then composite */ + if (mp_cmp (&y, &n1) != MP_EQ) { + goto __Y; + } + } + + /* probably prime now */ + *result = MP_YES; +__Y:mp_clear (&y); +__R:mp_clear (&r); +__N1:mp_clear (&n1); + return err; +} + +static const struct { + int k, t; +} sizes[] = { +{ 128, 28 }, +{ 256, 16 }, +{ 384, 10 }, +{ 512, 7 }, +{ 640, 6 }, +{ 768, 5 }, +{ 896, 4 }, +{ 1024, 4 } +}; + +/* returns # of RM trials required for a given bit size */ +int mp_prime_rabin_miller_trials(int size) +{ + int x; + + for (x = 0; x < (int)(sizeof(sizes)/(sizeof(sizes[0]))); x++) { + if (sizes[x].k == size) { + return sizes[x].t; + } else if (sizes[x].k > size) { + return (x == 0) ? sizes[0].t : sizes[x - 1].t; + } + } + return sizes[x-1].t + 1; +} + +/* makes a truly random prime of a given size (bits), + * + * Flags are as follows: + * + * LTM_PRIME_BBS - make prime congruent to 3 mod 4 + * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS) + * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero + * LTM_PRIME_2MSB_ON - make the 2nd highest bit one + * + * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can + * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself + * so it can be NULL + * + */ + +/* This is possibly the mother of all prime generation functions, muahahahahaha! */ +int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat) +{ + unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb; + int res, err, bsize, maskOR_msb_offset; + + /* sanity check the input */ + if (size <= 1 || t <= 0) { + return MP_VAL; + } + + /* LTM_PRIME_SAFE implies LTM_PRIME_BBS */ + if (flags & LTM_PRIME_SAFE) { + flags |= LTM_PRIME_BBS; + } + + /* calc the byte size */ + bsize = (size>>3)+((size&7)?1:0); + + /* we need a buffer of bsize bytes */ + tmp = malloc(bsize); + if (tmp == NULL) { + return MP_MEM; + } + + /* calc the maskAND value for the MSbyte*/ + maskAND = ((size&7) == 0) ? 0xFF : (0xFF >> (8 - (size & 7))); + + /* calc the maskOR_msb */ + maskOR_msb = 0; + maskOR_msb_offset = ((size & 7) == 1) ? 1 : 0; + if (flags & LTM_PRIME_2MSB_ON) { + maskOR_msb |= 1 << ((size - 2) & 7); + } else if (flags & LTM_PRIME_2MSB_OFF) { + maskAND &= ~(1 << ((size - 2) & 7)); + } + + /* get the maskOR_lsb */ + maskOR_lsb = 0; + if (flags & LTM_PRIME_BBS) { + maskOR_lsb |= 3; + } + + do { + /* read the bytes */ + if (cb(tmp, bsize, dat) != bsize) { + err = MP_VAL; + goto error; + } + + /* work over the MSbyte */ + tmp[0] &= maskAND; + tmp[0] |= 1 << ((size - 1) & 7); + + /* mix in the maskORs */ + tmp[maskOR_msb_offset] |= maskOR_msb; + tmp[bsize-1] |= maskOR_lsb; + + /* read it in */ + if ((err = mp_read_unsigned_bin(a, tmp, bsize)) != MP_OKAY) { goto error; } + + /* is it prime? */ + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { goto error; } + if (res == MP_NO) { + continue; + } + + if (flags & LTM_PRIME_SAFE) { + /* see if (a-1)/2 is prime */ + if ((err = mp_sub_d(a, 1, a)) != MP_OKAY) { goto error; } + if ((err = mp_div_2(a, a)) != MP_OKAY) { goto error; } + + /* is it prime? */ + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { goto error; } + } + } while (res == MP_NO); + + if (flags & LTM_PRIME_SAFE) { + /* restore a to the original value */ + if ((err = mp_mul_2(a, a)) != MP_OKAY) { goto error; } + if ((err = mp_add_d(a, 1, a)) != MP_OKAY) { goto error; } + } + + err = MP_OKAY; +error: + free(tmp); + return err; +} + +/* reads an unsigned char array, assumes the msb is stored first [big endian] */ +int +mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) +{ + int res; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((res = mp_grow(a, 2)) != MP_OKAY) { + return res; + } + } + + /* zero the int */ + mp_zero (a); + + /* read the bytes in */ + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + + a->dp[0] |= *b++; + a->used += 1; + } + mp_clamp (a); + return MP_OKAY; +} + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +int +mp_reduce (mp_int * x, const mp_int * m, const mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + /* q = x */ + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b**(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this optimization is ok */ + if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { + if ((res = s_mp_mul_high_digs (&q, mu, &q, um - 1)) != MP_OKAY) { + goto CLEANUP; + } + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) + goto CLEANUP; + if ((res = mp_add (x, &q, x)) != MP_OKAY) + goto CLEANUP; + } + + /* Back off if it's too big */ + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} + +/* reduces a modulo n where n is of the form 2**p - d */ +int +mp_reduce_2k(mp_int *a, const mp_int *n, mp_digit d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (d != 1) { + /* q = q * d */ + if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + +/* determines the setup value */ +int +mp_reduce_2k_setup(const mp_int *a, mp_digit *d) +{ + int res, p; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(a); + if ((res = mp_2expt(&tmp, p)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + *d = tmp.dp[0]; + mp_clear(&tmp); + return MP_OKAY; +} + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +int mp_reduce_setup (mp_int * a, const mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, b, a, NULL); +} + +/* shift right a certain amount of digits */ +void mp_rshd (mp_int * a, int b) +{ + int x; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero (a); + return; + } + + { + register mp_digit *bottom, *top; + + /* shift the digits down */ + + /* bottom */ + bottom = a->dp; + + /* top [offset into digits] */ + top = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *bottom++ = *top++; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + *bottom++ = 0; + } + } + + /* remove excess digits */ + a->used -= b; +} + +/* set to a digit */ +void mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} + +/* set a 32-bit const */ +int mp_set_int (mp_int * a, unsigned long b) +{ + int x, res; + + mp_zero (a); + + /* set four bits at a time */ + for (x = 0; x < 8; x++) { + /* shift the number up four bits */ + if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { + return res; + } + + /* OR in the top four bits of the source */ + a->dp[0] |= (b >> 28) & 15; + + /* shift the source up to the next four bits */ + b <<= 4; + + /* ensure that digits are not clamped off */ + a->used += 1; + } + mp_clamp (a); + return MP_OKAY; +} + +/* shrink a bignum */ +int mp_shrink (mp_int * a) +{ + mp_digit *tmp; + if (a->alloc != a->used && a->used > 0) { + if ((tmp = realloc (a->dp, sizeof (mp_digit) * a->used)) == NULL) { + return MP_MEM; + } + a->dp = tmp; + a->alloc = a->used; + } + return MP_OKAY; +} + +/* get the size for an signed equivalent */ +int mp_signed_bin_size (const mp_int * a) +{ + return 1 + mp_unsigned_bin_size (a); +} + +/* computes b = a*a */ +int +mp_sqr (const mp_int * a, mp_int * b) +{ + int res; + +if (a->used >= KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr (a, b); + } else + { + /* can we use the fast comba multiplier? */ + if ((a->used * 2 + 1) < MP_WARRAY && + a->used < + (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else + res = s_mp_sqr (a, b); + } + b->sign = MP_ZPOS; + return res; +} + +/* c = a * a (mod b) */ +int +mp_sqrmod (const mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sqr (a, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, b, c); + mp_clear (&t); + return res; +} + +/* high level subtraction (handles signs) */ +int +mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + sa = a->sign; + sb = b->sign; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag (a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + res = s_mp_sub (a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + +/* single digit subtraction */ +int +mp_sub_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit *tmpa, *tmpc, mu; + int res, ix, oldused; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative just do an unsigned + * addition [with fudged signs] + */ + if (a->sign == MP_NEG) { + a->sign = MP_ZPOS; + res = mp_add_d(a, b, c); + a->sign = c->sign = MP_NEG; + return res; + } + + /* setup regs */ + oldused = c->used; + tmpa = a->dp; + tmpc = c->dp; + + /* if a <= b simply fix the single digit */ + if ((a->used == 1 && a->dp[0] <= b) || a->used == 0) { + if (a->used == 1) { + *tmpc++ = b - *tmpa; + } else { + *tmpc++ = b; + } + ix = 1; + + /* negative/1digit */ + c->sign = MP_NEG; + c->used = 1; + } else { + /* positive/size */ + c->sign = MP_ZPOS; + c->used = a->used; + + /* subtract first digit */ + *tmpc = *tmpa++ - b; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + + /* handle rest of the digits */ + for (ix = 1; ix < a->used; ix++) { + *tmpc = *tmpa++ - mu; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + } + } + + /* zero excess digits */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + return MP_OKAY; +} + +/* store in unsigned [big endian] format */ +int +mp_to_unsigned_bin (const mp_int * a, unsigned char *b) +{ + int x, res; + mp_int t; + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + x = 0; + while (mp_iszero (&t) == 0) { + b[x++] = (unsigned char) (t.dp[0] & 255); + if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + bn_reverse (b, x); + mp_clear (&t); + return MP_OKAY; +} + +/* get the size for an unsigned equivalent */ +int +mp_unsigned_bin_size (const mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + +/* set to zero */ +void +mp_zero (mp_int * a) +{ + a->sign = MP_ZPOS; + a->used = 0; + memset (a->dp, 0, sizeof (mp_digit) * a->alloc); +} + +static const mp_digit __prime_tab[] = { + 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, + 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, + 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, + 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, + 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, + 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, + 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, + + 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, + 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, + 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, + 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, + 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, + 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, + 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, + 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, + + 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, + 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, + 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, + 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, + 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, + 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, + 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, + 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, + + 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, + 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, + 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, + 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, + 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, + 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, + 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, + 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 +}; + +/* reverse an array, used for radix code */ +void +bn_reverse (unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +int +s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < max + 1) { + if ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +int s_mp_exptmod (const mp_int * G, const mp_int * X, mp_int * P, mp_int * Y) +{ + mp_int M[256], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init (&mu)) != MP_OKAY) { + goto __M; + } + if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { + goto __MU; + } + + /* create M table + * + * The M table contains powers of the base, + * e.g. M[x] = G**x mod P + * + * The first half of the table is not + * computed though accept for M[0] and M[1] + */ + if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto __MU; + } + + /* compute the value at M[1<<(winsize-1)] by squaring + * M[1] (winsize-1) times + */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __MU; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], + &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { + goto __MU; + } + } + + /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) + * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) + */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&M[x], P, &mu)) != MP_OKAY) { + goto __MU; + } + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto __MU; + } + mp_set (&res, 1); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits */ + if (digidx == -1) { + break; + } + /* read next digit and reset the bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + } + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +__RES:mp_clear (&res); +__MU:mp_clear (&mu); +__M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + +/* multiplies |a| * |b| and only computes up to digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +int +s_mp_mul_digs (const mp_int * a, const mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MIN (b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry word from the result */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* set carry if it is placed below digs */ + if (ix + iy < digs) { + *tmpt = u; + } + } + + mp_clamp (&t); + mp_exch (&t, c); + + mp_clear (&t); + return MP_OKAY; +} + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +int +s_mp_mul_high_digs (const mp_int * a, const mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* get the lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* carry the carry */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +int +s_mp_sqr (const mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { + return res; + } + + /* default used is maximum possible size */ + t.used = 2*pa + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = ((mp_word) t.dp[2*ix]) + + ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]); + + /* store lower part in result */ + t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = t.dp + (2*ix + 1); + + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); + + /* now calculate the double precision result, note we use + * addition instead of *2 since it's easier to optimize + */ + r = ((mp_word) *tmpt) + r + r + ((mp_word) u); + + /* store lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + /* propagate upwards */ + while (u != ((mp_digit) 0)) { + r = ((mp_word) *tmpt) + ((mp_word) u); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +int +s_mp_sub (const mp_int * a, const mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = *tmpa++ - *tmpb++ - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is enough to get the carry + */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} diff --git a/reactos/dll/win32/rsaenh/rc2.c b/reactos/dll/win32/rsaenh/rc2.c new file mode 100644 index 00000000000..82b7bd3d694 --- /dev/null +++ b/reactos/dll/win32/rsaenh/rc2.c @@ -0,0 +1,203 @@ +/* + * dlls/rsaen/rc2.c + * RC2 functions + * + * Copyright 2004 Michael Jung + * Based on public domain code by Tom St Denis (tomstdenis@iahu.ca) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * This file contains code from the LibTomCrypt cryptographic + * library written by Tom St Denis (tomstdenis@iahu.ca). LibTomCrypt + * is in the public domain. The code in this file is tailored to + * special requirements. Take a look at http://libtomcrypt.org for the + * original version. + */ + +#include "tomcrypt.h" + +/* 256-entry permutation table, probably derived somehow from pi */ +static const unsigned char permute[256] = { + 217,120,249,196, 25,221,181,237, 40,233,253,121, 74,160,216,157, + 198,126, 55,131, 43,118, 83,142, 98, 76,100,136, 68,139,251,162, + 23,154, 89,245,135,179, 79, 19, 97, 69,109,141, 9,129,125, 50, + 189,143, 64,235,134,183,123, 11,240,149, 33, 34, 92,107, 78,130, + 84,214,101,147,206, 96,178, 28,115, 86,192, 20,167,140,241,220, + 18,117,202, 31, 59,190,228,209, 66, 61,212, 48,163, 60,182, 38, + 111,191, 14,218, 70,105, 7, 87, 39,242, 29,155,188,148, 67, 3, + 248, 17,199,246,144,239, 62,231, 6,195,213, 47,200,102, 30,215, + 8,232,234,222,128, 82,238,247,132,170,114,172, 53, 77,106, 42, + 150, 26,210,113, 90, 21, 73,116, 75,159,208, 94, 4, 24,164,236, + 194,224, 65,110, 15, 81,203,204, 36,145,175, 80,161,244,112, 57, + 153,124, 58,133, 35,184,180,122,252, 2, 54, 91, 37, 85,151, 49, + 45, 93,250,152,227,138,146,174, 5,223, 41, 16,103,108,186,201, + 211, 0,230,207,225,158,168, 44, 99, 22, 1, 63, 88,226,137,169, + 13, 56, 52, 27,171, 51,255,176,187, 72, 12, 95,185,177,205, 46, + 197,243,219, 71,229,165,156,119, 10,166, 32,104,254,127,193,173 +}; + +int rc2_setup(const unsigned char *key, int keylen, int bits, int rounds, rc2_key *rc2) +{ + unsigned *xkey = rc2->xkey; + unsigned char tmp[128]; + unsigned T8, TM; + int i; + + if (keylen < 5 || keylen > 128) { + return CRYPT_INVALID_KEYSIZE; + } + + if (rounds != 0 && rounds != 16) { + return CRYPT_INVALID_ROUNDS; + } + + /* Following comment is from Eric Young's rc2 code: */ + /* It has come to my attention that there are 2 versions of the RC2 + * key schedule. One which is normal, and anther which has a hook to + * use a reduced key length. + * BSAFE uses the 'retarded' version. What I previously shipped is + * the same as specifying 1024 for the 'bits' parameter. Bsafe uses + * a version where the bits parameter is the same as len*8 */ + /* Seems like MS uses the 'retarded' version, too. + * Adjust effective keylen bits */ + if (bits <= 0) bits = keylen << 3; + if (bits > 1024) bits = 1024; + + for (i = 0; i < keylen; i++) { + tmp[i] = key[i] & 255; + } + + /* Phase 1: Expand input key to 128 bytes */ + if (keylen < 128) { + for (i = keylen; i < 128; i++) { + tmp[i] = permute[(tmp[i - 1] + tmp[i - keylen]) & 255]; + } + } + + /* Phase 2 - reduce effective key size to "bits" */ + /*bits = keylen<<3; */ + T8 = (unsigned)(bits+7)>>3; + TM = (255 >> (unsigned)(7 & -bits)); + tmp[128 - T8] = permute[tmp[128 - T8] & TM]; + for (i = 127 - T8; i >= 0; i--) { + tmp[i] = permute[tmp[i + 1] ^ tmp[i + T8]]; + } + + /* Phase 3 - copy to xkey in little-endian order */ + for (i = 0; i < 64; i++) { + xkey[i] = (unsigned)tmp[2*i] + ((unsigned)tmp[2*i+1] << 8); + } + + return CRYPT_OK; +} + +/**********************************************************************\ +* Encrypt an 8-byte block of plaintext using the given key. * +\**********************************************************************/ +void rc2_ecb_encrypt( const unsigned char *plain, + unsigned char *cipher, + rc2_key *rc2) +{ + unsigned *xkey; + unsigned x76, x54, x32, x10, i; + + xkey = rc2->xkey; + + x76 = ((unsigned)plain[7] << 8) + (unsigned)plain[6]; + x54 = ((unsigned)plain[5] << 8) + (unsigned)plain[4]; + x32 = ((unsigned)plain[3] << 8) + (unsigned)plain[2]; + x10 = ((unsigned)plain[1] << 8) + (unsigned)plain[0]; + + for (i = 0; i < 16; i++) { + x10 = (x10 + (x32 & ~x76) + (x54 & x76) + xkey[4*i+0]) & 0xFFFF; + x10 = ((x10 << 1) | (x10 >> 15)); + + x32 = (x32 + (x54 & ~x10) + (x76 & x10) + xkey[4*i+1]) & 0xFFFF; + x32 = ((x32 << 2) | (x32 >> 14)); + + x54 = (x54 + (x76 & ~x32) + (x10 & x32) + xkey[4*i+2]) & 0xFFFF; + x54 = ((x54 << 3) | (x54 >> 13)); + + x76 = (x76 + (x10 & ~x54) + (x32 & x54) + xkey[4*i+3]) & 0xFFFF; + x76 = ((x76 << 5) | (x76 >> 11)); + + if (i == 4 || i == 10) { + x10 = (x10 + xkey[x76 & 63]) & 0xFFFF; + x32 = (x32 + xkey[x10 & 63]) & 0xFFFF; + x54 = (x54 + xkey[x32 & 63]) & 0xFFFF; + x76 = (x76 + xkey[x54 & 63]) & 0xFFFF; + } + } + + cipher[0] = (unsigned char)x10; + cipher[1] = (unsigned char)(x10 >> 8); + cipher[2] = (unsigned char)x32; + cipher[3] = (unsigned char)(x32 >> 8); + cipher[4] = (unsigned char)x54; + cipher[5] = (unsigned char)(x54 >> 8); + cipher[6] = (unsigned char)x76; + cipher[7] = (unsigned char)(x76 >> 8); +} + +/**********************************************************************\ +* Decrypt an 8-byte block of ciphertext using the given key. * +\**********************************************************************/ +void rc2_ecb_decrypt( const unsigned char *cipher, + unsigned char *plain, + rc2_key *rc2) +{ + unsigned x76, x54, x32, x10; + unsigned *xkey; + int i; + + xkey = rc2->xkey; + + x76 = ((unsigned)cipher[7] << 8) + (unsigned)cipher[6]; + x54 = ((unsigned)cipher[5] << 8) + (unsigned)cipher[4]; + x32 = ((unsigned)cipher[3] << 8) + (unsigned)cipher[2]; + x10 = ((unsigned)cipher[1] << 8) + (unsigned)cipher[0]; + + for (i = 15; i >= 0; i--) { + if (i == 4 || i == 10) { + x76 = (x76 - xkey[x54 & 63]) & 0xFFFF; + x54 = (x54 - xkey[x32 & 63]) & 0xFFFF; + x32 = (x32 - xkey[x10 & 63]) & 0xFFFF; + x10 = (x10 - xkey[x76 & 63]) & 0xFFFF; + } + + x76 = ((x76 << 11) | (x76 >> 5)); + x76 = (x76 - ((x10 & ~x54) + (x32 & x54) + xkey[4*i+3])) & 0xFFFF; + + x54 = ((x54 << 13) | (x54 >> 3)); + x54 = (x54 - ((x76 & ~x32) + (x10 & x32) + xkey[4*i+2])) & 0xFFFF; + + x32 = ((x32 << 14) | (x32 >> 2)); + x32 = (x32 - ((x54 & ~x10) + (x76 & x10) + xkey[4*i+1])) & 0xFFFF; + + x10 = ((x10 << 15) | (x10 >> 1)); + x10 = (x10 - ((x32 & ~x76) + (x54 & x76) + xkey[4*i+0])) & 0xFFFF; + } + + plain[0] = (unsigned char)x10; + plain[1] = (unsigned char)(x10 >> 8); + plain[2] = (unsigned char)x32; + plain[3] = (unsigned char)(x32 >> 8); + plain[4] = (unsigned char)x54; + plain[5] = (unsigned char)(x54 >> 8); + plain[6] = (unsigned char)x76; + plain[7] = (unsigned char)(x76 >> 8); +} diff --git a/reactos/dll/win32/rsaenh/rc4.c b/reactos/dll/win32/rsaenh/rc4.c new file mode 100644 index 00000000000..35f054b71cc --- /dev/null +++ b/reactos/dll/win32/rsaenh/rc4.c @@ -0,0 +1,108 @@ +/* + * dlls/rsaenh/rc4.c + * RC4 functions + * + * Copyright 2004 Michael Jung + * Based on public domain code by Tom St Denis (tomstdenis@iahu.ca) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * This file contains code from the LibTomCrypt cryptographic + * library written by Tom St Denis (tomstdenis@iahu.ca). LibTomCrypt + * is in the public domain. The code in this file is tailored to + * special requirements. Take a look at http://libtomcrypt.org for the + * original version. + */ + +#include "tomcrypt.h" + +int rc4_start(prng_state *prng) +{ + /* set keysize to zero */ + prng->rc4.x = 0; + + return CRYPT_OK; +} + +int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng) +{ + /* trim as required */ + if (prng->rc4.x + len > 256) { + if (prng->rc4.x == 256) { + /* I can't possibly accept another byte, ok maybe a mint wafer... */ + return CRYPT_OK; + } else { + /* only accept part of it */ + len = 256 - prng->rc4.x; + } + } + + while (len--) { + prng->rc4.buf[prng->rc4.x++] = *buf++; + } + + return CRYPT_OK; +} + +int rc4_ready(prng_state *prng) +{ + unsigned char key[256], tmp, *s; + int keylen, x, y, j; + + /* extract the key */ + s = prng->rc4.buf; + memcpy(key, s, 256); + keylen = prng->rc4.x; + + /* make RC4 perm and shuffle */ + for (x = 0; x < 256; x++) { + s[x] = x; + } + + for (j = x = y = 0; x < 256; x++) { + y = (y + prng->rc4.buf[x] + key[j++]) & 255; + if (j == keylen) { + j = 0; + } + tmp = s[x]; s[x] = s[y]; s[y] = tmp; + } + prng->rc4.x = 0; + prng->rc4.y = 0; + + return CRYPT_OK; +} + +unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng) +{ + unsigned char x, y, *s, tmp; + unsigned long n; + + n = len; + x = prng->rc4.x; + y = prng->rc4.y; + s = prng->rc4.buf; + while (len--) { + x = (x + 1) & 255; + y = (y + s[x]) & 255; + tmp = s[x]; s[x] = s[y]; s[y] = tmp; + tmp = (s[x] + s[y]) & 255; + *buf++ ^= s[tmp]; + } + prng->rc4.x = x; + prng->rc4.y = y; + return n; +} diff --git a/reactos/dll/win32/rsaenh/rsa.c b/reactos/dll/win32/rsaenh/rsa.c new file mode 100644 index 00000000000..5e9019f53d0 --- /dev/null +++ b/reactos/dll/win32/rsaenh/rsa.c @@ -0,0 +1,248 @@ +/* + * dlls/rsaenh/rsa.c + * RSA public key cryptographic functions + * + * Copyright 2004 Michael Jung + * Based on public domain code by Tom St Denis (tomstdenis@iahu.ca) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * This file contains code from the LibTomCrypt cryptographic + * library written by Tom St Denis (tomstdenis@iahu.ca). LibTomCrypt + * is in the public domain. The code in this file is tailored to + * special requirements. Take a look at http://libtomcrypt.org for the + * original version. + */ + +#include "tomcrypt.h" + +static const struct { + int mpi_code, ltc_code; +} mpi_to_ltc_codes[] = { + { MP_OKAY , CRYPT_OK}, + { MP_MEM , CRYPT_MEM}, + { MP_VAL , CRYPT_INVALID_ARG}, +}; + +/* convert a MPI error to a LTC error (Possibly the most powerful function ever! Oh wait... no) */ +static int mpi_to_ltc_error(int err) +{ + int x; + + for (x = 0; x < (int)(sizeof(mpi_to_ltc_codes)/sizeof(mpi_to_ltc_codes[0])); x++) { + if (err == mpi_to_ltc_codes[x].mpi_code) { + return mpi_to_ltc_codes[x].ltc_code; + } + } + return CRYPT_ERROR; +} + +extern int gen_rand_impl(unsigned char *dst, unsigned int len); + +static int rand_prime_helper(unsigned char *dst, int len, void *dat) +{ + return gen_rand_impl(dst, len) ? len : 0; +} + +static int rand_prime(mp_int *N, long len) +{ + int type; + + /* get type */ + if (len < 0) { + type = LTM_PRIME_BBS; + len = -len; + } else { + /* This seems to be what MS CSP's do: */ + type = LTM_PRIME_2MSB_ON; + /* Original LibTomCrypt: type = 0; */ + } + + /* allow sizes between 2 and 256 bytes for a prime size */ + if (len < 16 || len > 8192) { + printf("Invalid prime size!\n"); + return CRYPT_INVALID_PRIME_SIZE; + } + + /* New prime generation makes the code even more cryptoish-insane. Do you know what this means!!! + -- Gir: Yeah, oh wait, er, no. + */ + return mpi_to_ltc_error(mp_prime_random_ex(N, mp_prime_rabin_miller_trials(len), len, type, rand_prime_helper, NULL)); +} + +int rsa_make_key(int size, long e, rsa_key *key) +{ + mp_int p, q, tmp1, tmp2, tmp3; + int err; + + if ((size < (MIN_RSA_SIZE/8)) || (size > (MAX_RSA_SIZE/8))) { + return CRYPT_INVALID_KEYSIZE; + } + + if ((e < 3) || ((e & 1) == 0)) { + return CRYPT_INVALID_ARG; + } + + if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + /* make primes p and q (optimization provided by Wayne Scott) */ + if ((err = mp_set_int(&tmp3, e)) != MP_OKAY) { goto error; } /* tmp3 = e */ + + /* make prime "p" */ + do { + if ((err = rand_prime(&p, size*4)) != CRYPT_OK) { goto done; } + if ((err = mp_sub_d(&p, 1, &tmp1)) != MP_OKAY) { goto error; } /* tmp1 = p-1 */ + if ((err = mp_gcd(&tmp1, &tmp3, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = gcd(p-1, e) */ + } while (mp_cmp_d(&tmp2, 1) != 0); /* while e divides p-1 */ + + /* make prime "q" */ + do { + if ((err = rand_prime(&q, size*4)) != CRYPT_OK) { goto done; } + if ((err = mp_sub_d(&q, 1, &tmp1)) != MP_OKAY) { goto error; } /* tmp1 = q-1 */ + if ((err = mp_gcd(&tmp1, &tmp3, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = gcd(q-1, e) */ + } while (mp_cmp_d(&tmp2, 1) != 0); /* while e divides q-1 */ + + /* tmp1 = lcm(p-1, q-1) */ + if ((err = mp_sub_d(&p, 1, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = p-1 */ + /* tmp1 = q-1 (previous do/while loop) */ + if ((err = mp_lcm(&tmp1, &tmp2, &tmp1)) != MP_OKAY) { goto error; } /* tmp1 = lcm(p-1, q-1) */ + + /* make key */ + if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, + &key->qP, &key->p, &key->q, NULL)) != MP_OKAY) { + goto error; + } + + if ((err = mp_set_int(&key->e, e)) != MP_OKAY) { goto error2; } /* key->e = e */ + if ((err = mp_invmod(&key->e, &tmp1, &key->d)) != MP_OKAY) { goto error2; } /* key->d = 1/e mod lcm(p-1,q-1) */ + if ((err = mp_mul(&p, &q, &key->N)) != MP_OKAY) { goto error2; } /* key->N = pq */ + + /* optimize for CRT now */ + /* find d mod q-1 and d mod p-1 */ + if ((err = mp_sub_d(&p, 1, &tmp1)) != MP_OKAY) { goto error2; } /* tmp1 = q-1 */ + if ((err = mp_sub_d(&q, 1, &tmp2)) != MP_OKAY) { goto error2; } /* tmp2 = p-1 */ + if ((err = mp_mod(&key->d, &tmp1, &key->dP)) != MP_OKAY) { goto error2; } /* dP = d mod p-1 */ + if ((err = mp_mod(&key->d, &tmp2, &key->dQ)) != MP_OKAY) { goto error2; } /* dQ = d mod q-1 */ + if ((err = mp_invmod(&q, &p, &key->qP)) != MP_OKAY) { goto error2; } /* qP = 1/q mod p */ + + if ((err = mp_copy(&p, &key->p)) != MP_OKAY) { goto error2; } + if ((err = mp_copy(&q, &key->q)) != MP_OKAY) { goto error2; } + + /* shrink ram required */ + if ((err = mp_shrink(&key->e)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->d)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->N)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->dQ)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->dP)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->qP)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->p)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->q)) != MP_OKAY) { goto error2; } + + /* set key type (in this case it's CRT optimized) */ + key->type = PK_PRIVATE; + + /* return ok and free temps */ + err = CRYPT_OK; + goto done; +error2: + mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, + &key->qP, &key->p, &key->q, NULL); +error: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&tmp3, &tmp2, &tmp1, &p, &q, NULL); + return err; +} + +void rsa_free(rsa_key *key) +{ + mp_clear_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, + &key->qP, &key->p, &key->q, NULL); +} + +/* compute an RSA modular exponentiation */ +int rsa_exptmod(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, int which, + rsa_key *key) +{ + mp_int tmp, tmpa, tmpb; + unsigned long x; + int err; + + /* is the key of the right type for the operation? */ + if (which == PK_PRIVATE && (key->type != PK_PRIVATE)) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* must be a private or public operation */ + if (which != PK_PRIVATE && which != PK_PUBLIC) { + return CRYPT_PK_INVALID_TYPE; + } + + /* init and copy into tmp */ + if ((err = mp_init_multi(&tmp, &tmpa, &tmpb, NULL)) != MP_OKAY) { return mpi_to_ltc_error(err); } + if ((err = mp_read_unsigned_bin(&tmp, in, (int)inlen)) != MP_OKAY) { goto error; } + + /* sanity check on the input */ + if (mp_cmp(&key->N, &tmp) == MP_LT) { + err = CRYPT_PK_INVALID_SIZE; + goto done; + } + + /* are we using the private exponent and is the key optimized? */ + if (which == PK_PRIVATE) { + /* tmpa = tmp^dP mod p */ + if ((err = mpi_to_ltc_error(mp_exptmod(&tmp, &key->dP, &key->p, &tmpa))) != MP_OKAY) { goto error; } + + /* tmpb = tmp^dQ mod q */ + if ((err = mpi_to_ltc_error(mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb))) != MP_OKAY) { goto error; } + + /* tmp = (tmpa - tmpb) * qInv (mod p) */ + if ((err = mp_sub(&tmpa, &tmpb, &tmp)) != MP_OKAY) { goto error; } + if ((err = mp_mulmod(&tmp, &key->qP, &key->p, &tmp)) != MP_OKAY) { goto error; } + + /* tmp = tmpb + q * tmp */ + if ((err = mp_mul(&tmp, &key->q, &tmp)) != MP_OKAY) { goto error; } + if ((err = mp_add(&tmp, &tmpb, &tmp)) != MP_OKAY) { goto error; } + } else { + /* exptmod it */ + if ((err = mp_exptmod(&tmp, &key->e, &key->N, &tmp)) != MP_OKAY) { goto error; } + } + + /* read it back */ + x = (unsigned long)mp_unsigned_bin_size(&key->N); + if (x > *outlen) { + err = CRYPT_BUFFER_OVERFLOW; + goto done; + } + *outlen = x; + + /* convert it */ + memset(out, 0, x); + if ((err = mp_to_unsigned_bin(&tmp, out+(x-mp_unsigned_bin_size(&tmp)))) != MP_OKAY) { goto error; } + + /* clean up and return */ + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&tmp, &tmpa, &tmpb, NULL); + return err; +} diff --git a/reactos/dll/win32/rsaenh/rsaenh.c b/reactos/dll/win32/rsaenh/rsaenh.c new file mode 100644 index 00000000000..fff6474eeda --- /dev/null +++ b/reactos/dll/win32/rsaenh/rsaenh.c @@ -0,0 +1,3906 @@ +/* + * dlls/rsaenh/rsaenh.c + * RSAENH - RSA encryption for Wine + * + * Copyright 2002 TransGaming Technologies (David Hammerton) + * Copyright 2004 Mike McCormack for CodeWeavers + * Copyright 2004, 2005 Michael Jung + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" +#include "wine/library.h" +#include "wine/debug.h" + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "wincrypt.h" +#include "objbase.h" +#include "handle.h" +#include "implglue.h" + +WINE_DEFAULT_DEBUG_CHANNEL(crypt); + +/****************************************************************************** + * CRYPTHASH - hash objects + */ +#define RSAENH_MAGIC_HASH 0x85938417u +#define RSAENH_MAX_HASH_SIZE 104 +#define RSAENH_HASHSTATE_HASHING 1 +#define RSAENH_HASHSTATE_FINISHED 2 +typedef struct _RSAENH_TLS1PRF_PARAMS +{ + CRYPT_DATA_BLOB blobLabel; + CRYPT_DATA_BLOB blobSeed; +} RSAENH_TLS1PRF_PARAMS; + +typedef struct tagCRYPTHASH +{ + OBJECTHDR header; + ALG_ID aiAlgid; + HCRYPTKEY hKey; + HCRYPTPROV hProv; + DWORD dwHashSize; + DWORD dwState; + HASH_CONTEXT context; + BYTE abHashValue[RSAENH_MAX_HASH_SIZE]; + PHMAC_INFO pHMACInfo; + RSAENH_TLS1PRF_PARAMS tpPRFParams; +} CRYPTHASH; + +/****************************************************************************** + * CRYPTKEY - key objects + */ +#define RSAENH_MAGIC_KEY 0x73620457u +#define RSAENH_MAX_KEY_SIZE 48 +#define RSAENH_MAX_BLOCK_SIZE 24 +#define RSAENH_KEYSTATE_IDLE 0 +#define RSAENH_KEYSTATE_ENCRYPTING 1 +#define RSAENH_KEYSTATE_DECRYPTING 2 +#define RSAENH_KEYSTATE_MASTERKEY 3 +typedef struct _RSAENH_SCHANNEL_INFO +{ + SCHANNEL_ALG saEncAlg; + SCHANNEL_ALG saMACAlg; + CRYPT_DATA_BLOB blobClientRandom; + CRYPT_DATA_BLOB blobServerRandom; +} RSAENH_SCHANNEL_INFO; + +typedef struct tagCRYPTKEY +{ + OBJECTHDR header; + ALG_ID aiAlgid; + HCRYPTPROV hProv; + DWORD dwMode; + DWORD dwModeBits; + DWORD dwPermissions; + DWORD dwKeyLen; + DWORD dwEffectiveKeyLen; + DWORD dwSaltLen; + DWORD dwBlockLen; + DWORD dwState; + KEY_CONTEXT context; + BYTE abKeyValue[RSAENH_MAX_KEY_SIZE]; + BYTE abInitVector[RSAENH_MAX_BLOCK_SIZE]; + BYTE abChainVector[RSAENH_MAX_BLOCK_SIZE]; + RSAENH_SCHANNEL_INFO siSChannelInfo; +} CRYPTKEY; + +/****************************************************************************** + * KEYCONTAINER - key containers + */ +#define RSAENH_PERSONALITY_BASE 0u +#define RSAENH_PERSONALITY_STRONG 1u +#define RSAENH_PERSONALITY_ENHANCED 2u +#define RSAENH_PERSONALITY_SCHANNEL 3u + +#define RSAENH_MAGIC_CONTAINER 0x26384993u +typedef struct tagKEYCONTAINER +{ + OBJECTHDR header; + DWORD dwFlags; + DWORD dwPersonality; + DWORD dwEnumAlgsCtr; + DWORD dwEnumContainersCtr; + CHAR szName[MAX_PATH]; + CHAR szProvName[MAX_PATH]; + HCRYPTKEY hKeyExchangeKeyPair; + HCRYPTKEY hSignatureKeyPair; +} KEYCONTAINER; + +/****************************************************************************** + * Some magic constants + */ +#define RSAENH_ENCRYPT 1 +#define RSAENH_DECRYPT 0 +#define RSAENH_HMAC_DEF_IPAD_CHAR 0x36 +#define RSAENH_HMAC_DEF_OPAD_CHAR 0x5c +#define RSAENH_HMAC_DEF_PAD_LEN 64 +#define RSAENH_DES_EFFECTIVE_KEYLEN 56 +#define RSAENH_DES_STORAGE_KEYLEN 64 +#define RSAENH_3DES112_EFFECTIVE_KEYLEN 112 +#define RSAENH_3DES112_STORAGE_KEYLEN 128 +#define RSAENH_3DES_EFFECTIVE_KEYLEN 168 +#define RSAENH_3DES_STORAGE_KEYLEN 192 +#define RSAENH_MAGIC_RSA2 0x32415352 +#define RSAENH_MAGIC_RSA1 0x31415352 +#define RSAENH_PKC_BLOCKTYPE 0x02 +#define RSAENH_SSL3_VERSION_MAJOR 3 +#define RSAENH_SSL3_VERSION_MINOR 0 +#define RSAENH_TLS1_VERSION_MAJOR 3 +#define RSAENH_TLS1_VERSION_MINOR 1 +#define RSAENH_REGKEY "Software\\Wine\\Crypto\\RSA\\%s" + +#define RSAENH_MIN(a,b) ((a)<(b)?(a):(b)) +/****************************************************************************** + * aProvEnumAlgsEx - Defines the capabilities of the CSP personalities. + */ +#define RSAENH_MAX_ENUMALGS 20 +#define RSAENH_PCT1_SSL2_SSL3_TLS1 (CRYPT_FLAG_PCT1|CRYPT_FLAG_SSL2|CRYPT_FLAG_SSL3|CRYPT_FLAG_TLS1) +static const PROV_ENUMALGS_EX aProvEnumAlgsEx[4][RSAENH_MAX_ENUMALGS+1] = +{ + { + {CALG_RC2, 40, 40, 56,0, 4,"RC2", 24,"RSA Data Security's RC2"}, + {CALG_RC4, 40, 40, 56,0, 4,"RC4", 24,"RSA Data Security's RC4"}, + {CALG_DES, 56, 56, 56,0, 4,"DES", 31,"Data Encryption Standard (DES)"}, + {CALG_SHA, 160,160, 160,CRYPT_FLAG_SIGNING, 6,"SHA-1", 30,"Secure Hash Algorithm (SHA-1)"}, + {CALG_MD2, 128,128, 128,CRYPT_FLAG_SIGNING, 4,"MD2", 23,"Message Digest 2 (MD2)"}, + {CALG_MD4, 128,128, 128,CRYPT_FLAG_SIGNING, 4,"MD4", 23,"Message Digest 4 (MD4)"}, + {CALG_MD5, 128,128, 128,CRYPT_FLAG_SIGNING, 4,"MD5", 23,"Message Digest 5 (MD5)"}, + {CALG_SSL3_SHAMD5,288,288,288,0, 12,"SSL3 SHAMD5",12,"SSL3 SHAMD5"}, + {CALG_MAC, 0, 0, 0,0, 4,"MAC", 28,"Message Authentication Code"}, + {CALG_RSA_SIGN, 512,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_SIGN",14,"RSA Signature"}, + {CALG_RSA_KEYX, 512,384, 1024,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_KEYX",17,"RSA Key Exchange"}, + {CALG_HMAC, 0, 0, 0,0, 5,"HMAC", 18,"Hugo's MAC (HMAC)"}, + {0, 0, 0, 0,0, 1,"", 1,""} + }, + { + {CALG_RC2, 128, 40, 128,0, 4,"RC2", 24,"RSA Data Security's RC2"}, + {CALG_RC4, 128, 40, 128,0, 4,"RC4", 24,"RSA Data Security's RC4"}, + {CALG_DES, 56, 56, 56,0, 4,"DES", 31,"Data Encryption Standard (DES)"}, + {CALG_3DES_112, 112,112, 112,0, 13,"3DES TWO KEY",19,"Two Key Triple DES"}, + {CALG_3DES, 168,168, 168,0, 5,"3DES", 21,"Three Key Triple DES"}, + {CALG_SHA, 160,160, 160,CRYPT_FLAG_SIGNING, 6,"SHA-1", 30,"Secure Hash Algorithm (SHA-1)"}, + {CALG_MD2, 128,128, 128,CRYPT_FLAG_SIGNING, 4,"MD2", 23,"Message Digest 2 (MD2)"}, + {CALG_MD4, 128,128, 128,CRYPT_FLAG_SIGNING, 4,"MD4", 23,"Message Digest 4 (MD4)"}, + {CALG_MD5, 128,128, 128,CRYPT_FLAG_SIGNING, 4,"MD5", 23,"Message Digest 5 (MD5)"}, + {CALG_SSL3_SHAMD5,288,288,288,0, 12,"SSL3 SHAMD5",12,"SSL3 SHAMD5"}, + {CALG_MAC, 0, 0, 0,0, 4,"MAC", 28,"Message Authentication Code"}, + {CALG_RSA_SIGN,1024,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_SIGN",14,"RSA Signature"}, + {CALG_RSA_KEYX,1024,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_KEYX",17,"RSA Key Exchange"}, + {CALG_HMAC, 0, 0, 0,0, 5,"HMAC", 18,"Hugo's MAC (HMAC)"}, + {0, 0, 0, 0,0, 1,"", 1,""} + }, + { + {CALG_RC2, 128, 40, 128,0, 4,"RC2", 24,"RSA Data Security's RC2"}, + {CALG_RC4, 128, 40, 128,0, 4,"RC4", 24,"RSA Data Security's RC4"}, + {CALG_DES, 56, 56, 56,0, 4,"DES", 31,"Data Encryption Standard (DES)"}, + {CALG_3DES_112, 112,112, 112,0, 13,"3DES TWO KEY",19,"Two Key Triple DES"}, + {CALG_3DES, 168,168, 168,0, 5,"3DES", 21,"Three Key Triple DES"}, + {CALG_SHA, 160,160, 160,CRYPT_FLAG_SIGNING, 6,"SHA-1", 30,"Secure Hash Algorithm (SHA-1)"}, + {CALG_MD2, 128,128, 128,CRYPT_FLAG_SIGNING, 4,"MD2", 23,"Message Digest 2 (MD2)"}, + {CALG_MD4, 128,128, 128,CRYPT_FLAG_SIGNING, 4,"MD4", 23,"Message Digest 4 (MD4)"}, + {CALG_MD5, 128,128, 128,CRYPT_FLAG_SIGNING, 4,"MD5", 23,"Message Digest 5 (MD5)"}, + {CALG_SSL3_SHAMD5,288,288,288,0, 12,"SSL3 SHAMD5",12,"SSL3 SHAMD5"}, + {CALG_MAC, 0, 0, 0,0, 4,"MAC", 28,"Message Authentication Code"}, + {CALG_RSA_SIGN,1024,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_SIGN",14,"RSA Signature"}, + {CALG_RSA_KEYX,1024,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_KEYX",17,"RSA Key Exchange"}, + {CALG_HMAC, 0, 0, 0,0, 5,"HMAC", 18,"Hugo's MAC (HMAC)"}, + {0, 0, 0, 0,0, 1,"", 1,""} + }, + { + {CALG_RC2, 128, 40, 128,RSAENH_PCT1_SSL2_SSL3_TLS1, 4,"RC2", 24,"RSA Data Security's RC2"}, + {CALG_RC4, 128, 40, 128,RSAENH_PCT1_SSL2_SSL3_TLS1, 4,"RC4", 24,"RSA Data Security's RC4"}, + {CALG_DES, 56, 56, 56,RSAENH_PCT1_SSL2_SSL3_TLS1, 4,"DES", 31,"Data Encryption Standard (DES)"}, + {CALG_3DES_112, 112,112, 112,RSAENH_PCT1_SSL2_SSL3_TLS1,13,"3DES TWO KEY",19,"Two Key Triple DES"}, + {CALG_3DES, 168,168, 168,RSAENH_PCT1_SSL2_SSL3_TLS1, 5,"3DES", 21,"Three Key Triple DES"}, + {CALG_SHA,160,160,160,CRYPT_FLAG_SIGNING|RSAENH_PCT1_SSL2_SSL3_TLS1,6,"SHA-1",30,"Secure Hash Algorithm (SHA-1)"}, + {CALG_MD5,128,128,128,CRYPT_FLAG_SIGNING|RSAENH_PCT1_SSL2_SSL3_TLS1,4,"MD5",23,"Message Digest 5 (MD5)"}, + {CALG_SSL3_SHAMD5,288,288,288,0, 12,"SSL3 SHAMD5",12,"SSL3 SHAMD5"}, + {CALG_MAC, 0, 0, 0,0, 4,"MAC", 28,"Message Authentication Code"}, + {CALG_RSA_SIGN,1024,384,16384,CRYPT_FLAG_SIGNING|RSAENH_PCT1_SSL2_SSL3_TLS1,9,"RSA_SIGN",14,"RSA Signature"}, + {CALG_RSA_KEYX,1024,384,16384,CRYPT_FLAG_SIGNING|RSAENH_PCT1_SSL2_SSL3_TLS1,9,"RSA_KEYX",17,"RSA Key Exchange"}, + {CALG_HMAC, 0, 0, 0,0, 5,"HMAC", 18,"Hugo's MAC (HMAC)"}, + {CALG_PCT1_MASTER,128,128,128,CRYPT_FLAG_PCT1, 12,"PCT1 MASTER",12,"PCT1 Master"}, + {CALG_SSL2_MASTER,40,40, 192,CRYPT_FLAG_SSL2, 12,"SSL2 MASTER",12,"SSL2 Master"}, + {CALG_SSL3_MASTER,384,384,384,CRYPT_FLAG_SSL3, 12,"SSL3 MASTER",12,"SSL3 Master"}, + {CALG_TLS1_MASTER,384,384,384,CRYPT_FLAG_TLS1, 12,"TLS1 MASTER",12,"TLS1 Master"}, + {CALG_SCHANNEL_MASTER_HASH,0,0,-1,0, 16,"SCH MASTER HASH",21,"SChannel Master Hash"}, + {CALG_SCHANNEL_MAC_KEY,0,0,-1,0, 12,"SCH MAC KEY",17,"SChannel MAC Key"}, + {CALG_SCHANNEL_ENC_KEY,0,0,-1,0, 12,"SCH ENC KEY",24,"SChannel Encryption Key"}, + {CALG_TLS1PRF, 0, 0, -1,0, 9,"TLS1 PRF", 28,"TLS1 Pseudo Random Function"}, + {0, 0, 0, 0,0, 1,"", 1,""} + } +}; + +/****************************************************************************** + * API forward declarations + */ +BOOL WINAPI +RSAENH_CPGetKeyParam( + HCRYPTPROV hProv, + HCRYPTKEY hKey, + DWORD dwParam, + BYTE *pbData, + DWORD *pdwDataLen, + DWORD dwFlags +); + +BOOL WINAPI +RSAENH_CPEncrypt( + HCRYPTPROV hProv, + HCRYPTKEY hKey, + HCRYPTHASH hHash, + BOOL Final, + DWORD dwFlags, + BYTE *pbData, + DWORD *pdwDataLen, + DWORD dwBufLen +); + +BOOL WINAPI +RSAENH_CPCreateHash( + HCRYPTPROV hProv, + ALG_ID Algid, + HCRYPTKEY hKey, + DWORD dwFlags, + HCRYPTHASH *phHash +); + +BOOL WINAPI +RSAENH_CPSetHashParam( + HCRYPTPROV hProv, + HCRYPTHASH hHash, + DWORD dwParam, + BYTE *pbData, DWORD dwFlags +); + +BOOL WINAPI +RSAENH_CPGetHashParam( + HCRYPTPROV hProv, + HCRYPTHASH hHash, + DWORD dwParam, + BYTE *pbData, + DWORD *pdwDataLen, + DWORD dwFlags +); + +BOOL WINAPI +RSAENH_CPDestroyHash( + HCRYPTPROV hProv, + HCRYPTHASH hHash +); + +BOOL WINAPI +RSAENH_CPExportKey( + HCRYPTPROV hProv, + HCRYPTKEY hKey, + HCRYPTKEY hPubKey, + DWORD dwBlobType, + DWORD dwFlags, + BYTE *pbData, + DWORD *pdwDataLen +); + +BOOL WINAPI +RSAENH_CPImportKey( + HCRYPTPROV hProv, + CONST BYTE *pbData, + DWORD dwDataLen, + HCRYPTKEY hPubKey, + DWORD dwFlags, + HCRYPTKEY *phKey +); + +BOOL WINAPI +RSAENH_CPHashData( + HCRYPTPROV hProv, + HCRYPTHASH hHash, + CONST BYTE *pbData, + DWORD dwDataLen, + DWORD dwFlags +); + +/****************************************************************************** + * CSP's handle table (used by all acquired key containers) + */ +static HANDLETABLE handle_table; + +/****************************************************************************** + * DllMain (RSAENH.@) + * + * Initializes and destroys the handle table for the CSP's handles. + */ +int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInstance); + init_handle_table(&handle_table); + break; + + case DLL_PROCESS_DETACH: + destroy_handle_table(&handle_table); + break; + } + return 1; +} + +/****************************************************************************** + * copy_param [Internal] + * + * Helper function that supports the standard WINAPI protocol for querying data + * of dynamic size. + * + * PARAMS + * pbBuffer [O] Buffer where the queried parameter is copied to, if it is large enough. + * May be NUL if the required buffer size is to be queried only. + * pdwBufferSize [I/O] In: Size of the buffer at pbBuffer + * Out: Size of parameter pbParam + * pbParam [I] Parameter value. + * dwParamSize [I] Size of pbParam + * + * RETURN + * Success: TRUE (pbParam was copied into pbBuffer or pbBuffer is NULL) + * Failure: FALSE (pbBuffer is not large enough to hold pbParam). Last error: ERROR_MORE_DATA + */ +static inline BOOL copy_param( + BYTE *pbBuffer, DWORD *pdwBufferSize, CONST BYTE *pbParam, DWORD dwParamSize) +{ + if (pbBuffer) + { + if (dwParamSize > *pdwBufferSize) + { + SetLastError(ERROR_MORE_DATA); + *pdwBufferSize = dwParamSize; + return FALSE; + } + memcpy(pbBuffer, pbParam, dwParamSize); + } + *pdwBufferSize = dwParamSize; + return TRUE; +} + +/****************************************************************************** + * get_algid_info [Internal] + * + * Query CSP capabilities for a given crypto algorithm. + * + * PARAMS + * hProv [I] Handle to a key container of the CSP whose capabilities are to be queried. + * algid [I] Identifier of the crypto algorithm about which information is requested. + * + * RETURNS + * Success: Pointer to a PROV_ENUMALGS_EX struct containing information about the crypto algorithm. + * Failure: NULL (algid not supported) + */ +static inline const PROV_ENUMALGS_EX* get_algid_info(HCRYPTPROV hProv, ALG_ID algid) { + const PROV_ENUMALGS_EX *iterator; + KEYCONTAINER *pKeyContainer; + + if (!lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER, (OBJECTHDR**)&pKeyContainer)) { + SetLastError(NTE_BAD_UID); + return NULL; + } + + for (iterator = aProvEnumAlgsEx[pKeyContainer->dwPersonality]; iterator->aiAlgid; iterator++) { + if (iterator->aiAlgid == algid) return iterator; + } + + SetLastError(NTE_BAD_ALGID); + return NULL; +} + +/****************************************************************************** + * copy_data_blob [Internal] + * + * deeply copies a DATA_BLOB + * + * PARAMS + * dst [O] That's where the blob will be copied to + * src [I] Source blob + * + * RETURNS + * Success: TRUE + * Failure: FALSE (GetLastError() == NTE_NO_MEMORY + * + * NOTES + * Use free_data_blob to release resources occupied by copy_data_blob. + */ +static inline BOOL copy_data_blob(PCRYPT_DATA_BLOB dst, CONST PCRYPT_DATA_BLOB src) { + dst->pbData = HeapAlloc(GetProcessHeap(), 0, src->cbData); + if (!dst->pbData) { + SetLastError(NTE_NO_MEMORY); + return FALSE; + } + dst->cbData = src->cbData; + memcpy(dst->pbData, src->pbData, src->cbData); + return TRUE; +} + +/****************************************************************************** + * concat_data_blobs [Internal] + * + * Concatenates two blobs + * + * PARAMS + * dst [O] The new blob will be copied here + * src1 [I] Prefix blob + * src2 [I] Appendix blob + * + * RETURNS + * Success: TRUE + * Failure: FALSE (GetLastError() == NTE_NO_MEMORY) + * + * NOTES + * Release resources occupied by concat_data_blobs with free_data_blobs + */ +static inline BOOL concat_data_blobs(PCRYPT_DATA_BLOB dst, CONST PCRYPT_DATA_BLOB src1, + CONST PCRYPT_DATA_BLOB src2) +{ + dst->cbData = src1->cbData + src2->cbData; + dst->pbData = HeapAlloc(GetProcessHeap(), 0, dst->cbData); + if (!dst->pbData) { + SetLastError(NTE_NO_MEMORY); + return FALSE; + } + memcpy(dst->pbData, src1->pbData, src1->cbData); + memcpy(dst->pbData + src1->cbData, src2->pbData, src2->cbData); + return TRUE; +} + +/****************************************************************************** + * free_data_blob [Internal] + * + * releases resource occupied by a dynamically allocated CRYPT_DATA_BLOB + * + * PARAMS + * pBlob [I] Heap space occupied by pBlob->pbData is released + */ +static inline void free_data_blob(PCRYPT_DATA_BLOB pBlob) { + HeapFree(GetProcessHeap(), 0, pBlob->pbData); +} + +/****************************************************************************** + * init_data_blob [Internal] + */ +static inline void init_data_blob(PCRYPT_DATA_BLOB pBlob) { + pBlob->pbData = NULL; + pBlob->cbData = 0; +} + +/****************************************************************************** + * free_hmac_info [Internal] + * + * Deeply free an HMAC_INFO struct. + * + * PARAMS + * hmac_info [I] Pointer to the HMAC_INFO struct to be freed. + * + * NOTES + * See Internet RFC 2104 for details on the HMAC algorithm. + */ +static inline void free_hmac_info(PHMAC_INFO hmac_info) { + if (!hmac_info) return; + HeapFree(GetProcessHeap(), 0, hmac_info->pbInnerString); + HeapFree(GetProcessHeap(), 0, hmac_info->pbOuterString); + HeapFree(GetProcessHeap(), 0, hmac_info); +} + +/****************************************************************************** + * copy_hmac_info [Internal] + * + * Deeply copy an HMAC_INFO struct + * + * PARAMS + * dst [O] Pointer to a location where the pointer to the HMAC_INFO copy will be stored. + * src [I] Pointer to the HMAC_INFO struct to be copied. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * See Internet RFC 2104 for details on the HMAC algorithm. + */ +static BOOL copy_hmac_info(PHMAC_INFO *dst, const HMAC_INFO *src) { + if (!src) return FALSE; + *dst = HeapAlloc(GetProcessHeap(), 0, sizeof(HMAC_INFO)); + if (!*dst) return FALSE; + memcpy(*dst, src, sizeof(HMAC_INFO)); + (*dst)->pbInnerString = NULL; + (*dst)->pbOuterString = NULL; + if ((*dst)->cbInnerString == 0) (*dst)->cbInnerString = RSAENH_HMAC_DEF_PAD_LEN; + (*dst)->pbInnerString = HeapAlloc(GetProcessHeap(), 0, (*dst)->cbInnerString); + if (!(*dst)->pbInnerString) { + free_hmac_info(*dst); + return FALSE; + } + if (src->cbInnerString) + memcpy((*dst)->pbInnerString, src->pbInnerString, src->cbInnerString); + else + memset((*dst)->pbInnerString, RSAENH_HMAC_DEF_IPAD_CHAR, RSAENH_HMAC_DEF_PAD_LEN); + if ((*dst)->cbOuterString == 0) (*dst)->cbOuterString = RSAENH_HMAC_DEF_PAD_LEN; + (*dst)->pbOuterString = HeapAlloc(GetProcessHeap(), 0, (*dst)->cbOuterString); + if (!(*dst)->pbOuterString) { + free_hmac_info(*dst); + return FALSE; + } + if (src->cbOuterString) + memcpy((*dst)->pbOuterString, src->pbOuterString, src->cbOuterString); + else + memset((*dst)->pbOuterString, RSAENH_HMAC_DEF_OPAD_CHAR, RSAENH_HMAC_DEF_PAD_LEN); + return TRUE; +} + +/****************************************************************************** + * destroy_hash [Internal] + * + * Destructor for hash objects + * + * PARAMS + * pCryptHash [I] Pointer to the hash object to be destroyed. + * Will be invalid after function returns! + */ +static void destroy_hash(OBJECTHDR *pObject) +{ + CRYPTHASH *pCryptHash = (CRYPTHASH*)pObject; + + free_hmac_info(pCryptHash->pHMACInfo); + free_data_blob(&pCryptHash->tpPRFParams.blobLabel); + free_data_blob(&pCryptHash->tpPRFParams.blobSeed); + HeapFree(GetProcessHeap(), 0, pCryptHash); +} + +/****************************************************************************** + * init_hash [Internal] + * + * Initialize (or reset) a hash object + * + * PARAMS + * pCryptHash [I] The hash object to be initialized. + */ +static inline BOOL init_hash(CRYPTHASH *pCryptHash) { + DWORD dwLen; + + switch (pCryptHash->aiAlgid) + { + case CALG_HMAC: + if (pCryptHash->pHMACInfo) { + const PROV_ENUMALGS_EX *pAlgInfo; + + pAlgInfo = get_algid_info(pCryptHash->hProv, pCryptHash->pHMACInfo->HashAlgid); + if (!pAlgInfo) return FALSE; + pCryptHash->dwHashSize = pAlgInfo->dwDefaultLen >> 3; + init_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->context); + update_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->context, + pCryptHash->pHMACInfo->pbInnerString, + pCryptHash->pHMACInfo->cbInnerString); + } + return TRUE; + + case CALG_MAC: + dwLen = sizeof(DWORD); + RSAENH_CPGetKeyParam(pCryptHash->hProv, pCryptHash->hKey, KP_BLOCKLEN, + (BYTE*)&pCryptHash->dwHashSize, &dwLen, 0); + pCryptHash->dwHashSize >>= 3; + return TRUE; + + default: + return init_hash_impl(pCryptHash->aiAlgid, &pCryptHash->context); + } +} + +/****************************************************************************** + * update_hash [Internal] + * + * Hashes the given data and updates the hash object's state accordingly + * + * PARAMS + * pCryptHash [I] Hash object to be updated. + * pbData [I] Pointer to data stream to be hashed. + * dwDataLen [I] Length of data stream. + */ +static inline void update_hash(CRYPTHASH *pCryptHash, CONST BYTE *pbData, DWORD dwDataLen) { + BYTE *pbTemp; + + switch (pCryptHash->aiAlgid) + { + case CALG_HMAC: + if (pCryptHash->pHMACInfo) + update_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->context, + pbData, dwDataLen); + break; + + case CALG_MAC: + pbTemp = HeapAlloc(GetProcessHeap(), 0, dwDataLen); + if (!pbTemp) return; + memcpy(pbTemp, pbData, dwDataLen); + RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, (HCRYPTHASH)NULL, FALSE, 0, + pbTemp, &dwDataLen, dwDataLen); + HeapFree(GetProcessHeap(), 0, pbTemp); + break; + + default: + update_hash_impl(pCryptHash->aiAlgid, &pCryptHash->context, pbData, dwDataLen); + } +} + +/****************************************************************************** + * finalize_hash [Internal] + * + * Finalizes the hash, after all data has been hashed with update_hash. + * No additional data can be hashed afterwards until the hash gets initialized again. + * + * PARAMS + * pCryptHash [I] Hash object to be finalized. + */ +static inline void finalize_hash(CRYPTHASH *pCryptHash) { + DWORD dwDataLen; + + switch (pCryptHash->aiAlgid) + { + case CALG_HMAC: + if (pCryptHash->pHMACInfo) { + BYTE abHashValue[RSAENH_MAX_HASH_SIZE]; + + finalize_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->context, + pCryptHash->abHashValue); + memcpy(abHashValue, pCryptHash->abHashValue, pCryptHash->dwHashSize); + init_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->context); + update_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->context, + pCryptHash->pHMACInfo->pbOuterString, + pCryptHash->pHMACInfo->cbOuterString); + update_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->context, + abHashValue, pCryptHash->dwHashSize); + finalize_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->context, + pCryptHash->abHashValue); + } + break; + + case CALG_MAC: + dwDataLen = 0; + RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, (HCRYPTHASH)NULL, TRUE, 0, + pCryptHash->abHashValue, &dwDataLen, pCryptHash->dwHashSize); + break; + + default: + finalize_hash_impl(pCryptHash->aiAlgid, &pCryptHash->context, pCryptHash->abHashValue); + } +} + +/****************************************************************************** + * destroy_key [Internal] + * + * Destructor for key objects + * + * PARAMS + * pCryptKey [I] Pointer to the key object to be destroyed. + * Will be invalid after function returns! + */ +static void destroy_key(OBJECTHDR *pObject) +{ + CRYPTKEY *pCryptKey = (CRYPTKEY*)pObject; + + free_key_impl(pCryptKey->aiAlgid, &pCryptKey->context); + free_data_blob(&pCryptKey->siSChannelInfo.blobClientRandom); + free_data_blob(&pCryptKey->siSChannelInfo.blobServerRandom); + HeapFree(GetProcessHeap(), 0, pCryptKey); +} + +/****************************************************************************** + * setup_key [Internal] + * + * Initialize (or reset) a key object + * + * PARAMS + * pCryptKey [I] The key object to be initialized. + */ +static inline void setup_key(CRYPTKEY *pCryptKey) { + pCryptKey->dwState = RSAENH_KEYSTATE_IDLE; + memcpy(pCryptKey->abChainVector, pCryptKey->abInitVector, sizeof(pCryptKey->abChainVector)); + setup_key_impl(pCryptKey->aiAlgid, &pCryptKey->context, pCryptKey->dwKeyLen, + pCryptKey->dwEffectiveKeyLen, pCryptKey->dwSaltLen, + pCryptKey->abKeyValue); +} + +/****************************************************************************** + * new_key [Internal] + * + * Creates a new key object without assigning the actual binary key value. + * This is done by CPDeriveKey, CPGenKey or CPImportKey, which call this function. + * + * PARAMS + * hProv [I] Handle to the provider to which the created key will belong. + * aiAlgid [I] The new key shall use the crypto algorithm idenfied by aiAlgid. + * dwFlags [I] Upper 16 bits give the key length. + * Lower 16 bits: CRYPT_CREATE_SALT, CRYPT_NO_SALT + * ppCryptKey [O] Pointer to the created key + * + * RETURNS + * Success: Handle to the created key. + * Failure: INVALID_HANDLE_VALUE + */ +static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, CRYPTKEY **ppCryptKey) +{ + HCRYPTKEY hCryptKey; + CRYPTKEY *pCryptKey; + DWORD dwKeyLen = HIWORD(dwFlags); + const PROV_ENUMALGS_EX *peaAlgidInfo; + + *ppCryptKey = NULL; + + /* + * Retrieve the CSP's capabilities for the given ALG_ID value + */ + peaAlgidInfo = get_algid_info(hProv, aiAlgid); + if (!peaAlgidInfo) return (HCRYPTKEY)INVALID_HANDLE_VALUE; + + /* + * Assume the default key length, if none is specified explicitly + */ + if (dwKeyLen == 0) dwKeyLen = peaAlgidInfo->dwDefaultLen; + + /* + * Check if the requested key length is supported by the current CSP. + * Adjust key length's for DES algorithms. + */ + switch (aiAlgid) { + case CALG_DES: + if (dwKeyLen == RSAENH_DES_EFFECTIVE_KEYLEN) { + dwKeyLen = RSAENH_DES_STORAGE_KEYLEN; + } + if (dwKeyLen != RSAENH_DES_STORAGE_KEYLEN) { + SetLastError(NTE_BAD_FLAGS); + return (HCRYPTKEY)INVALID_HANDLE_VALUE; + } + break; + + case CALG_3DES_112: + if (dwKeyLen == RSAENH_3DES112_EFFECTIVE_KEYLEN) { + dwKeyLen = RSAENH_3DES112_STORAGE_KEYLEN; + } + if (dwKeyLen != RSAENH_3DES112_STORAGE_KEYLEN) { + SetLastError(NTE_BAD_FLAGS); + return (HCRYPTKEY)INVALID_HANDLE_VALUE; + } + break; + + case CALG_3DES: + if (dwKeyLen == RSAENH_3DES_EFFECTIVE_KEYLEN) { + dwKeyLen = RSAENH_3DES_STORAGE_KEYLEN; + } + if (dwKeyLen != RSAENH_3DES_STORAGE_KEYLEN) { + SetLastError(NTE_BAD_FLAGS); + return (HCRYPTKEY)INVALID_HANDLE_VALUE; + } + break; + + default: + if (dwKeyLen % 8 || + dwKeyLen > peaAlgidInfo->dwMaxLen || + dwKeyLen < peaAlgidInfo->dwMinLen) + { + SetLastError(NTE_BAD_FLAGS); + return (HCRYPTKEY)INVALID_HANDLE_VALUE; + } + } + + hCryptKey = (HCRYPTKEY)new_object(&handle_table, sizeof(CRYPTKEY), RSAENH_MAGIC_KEY, + destroy_key, (OBJECTHDR**)&pCryptKey); + if (hCryptKey != (HCRYPTKEY)INVALID_HANDLE_VALUE) + { + pCryptKey->aiAlgid = aiAlgid; + pCryptKey->hProv = hProv; + pCryptKey->dwModeBits = 0; + pCryptKey->dwPermissions = CRYPT_ENCRYPT | CRYPT_DECRYPT | CRYPT_READ | CRYPT_WRITE | + CRYPT_MAC; + pCryptKey->dwKeyLen = dwKeyLen >> 3; + pCryptKey->dwEffectiveKeyLen = 0; + if ((dwFlags & CRYPT_CREATE_SALT) || (dwKeyLen == 40 && !(dwFlags & CRYPT_NO_SALT))) + pCryptKey->dwSaltLen = 16 /*FIXME*/ - pCryptKey->dwKeyLen; + else + pCryptKey->dwSaltLen = 0; + memset(pCryptKey->abKeyValue, 0, sizeof(pCryptKey->abKeyValue)); + memset(pCryptKey->abInitVector, 0, sizeof(pCryptKey->abInitVector)); + init_data_blob(&pCryptKey->siSChannelInfo.blobClientRandom); + init_data_blob(&pCryptKey->siSChannelInfo.blobServerRandom); + + switch(aiAlgid) + { + case CALG_PCT1_MASTER: + case CALG_SSL2_MASTER: + case CALG_SSL3_MASTER: + case CALG_TLS1_MASTER: + case CALG_RC4: + pCryptKey->dwBlockLen = 0; + pCryptKey->dwMode = 0; + break; + + case CALG_RC2: + case CALG_DES: + case CALG_3DES_112: + case CALG_3DES: + pCryptKey->dwBlockLen = 8; + pCryptKey->dwMode = CRYPT_MODE_CBC; + break; + + case CALG_RSA_KEYX: + case CALG_RSA_SIGN: + pCryptKey->dwBlockLen = dwKeyLen >> 3; + pCryptKey->dwMode = 0; + break; + } + + *ppCryptKey = pCryptKey; + } + + return hCryptKey; +} + +/****************************************************************************** + * store_key_pair [Internal] + * + * Stores a key pair to the registry + * + * PARAMS + * hCryptKey [I] Handle to the key to be stored + * hKey [I] Registry key where the key pair is to be stored + * szValueName [I] Registry value where key pair's value is to be stored + * dwFlags [I] Flags for protecting the key + */ +static void store_key_pair(HCRYPTKEY hCryptKey, HKEY hKey, LPCSTR szValueName, DWORD dwFlags) +{ + DATA_BLOB blobIn, blobOut; + CRYPTKEY *pKey; + DWORD dwLen; + BYTE *pbKey; + + if (lookup_handle(&handle_table, hCryptKey, RSAENH_MAGIC_KEY, + (OBJECTHDR**)&pKey)) + { + if (RSAENH_CPExportKey(pKey->hProv, hCryptKey, 0, PRIVATEKEYBLOB, 0, 0, + &dwLen)) + { + pbKey = HeapAlloc(GetProcessHeap(), 0, dwLen); + if (pbKey) + { + if (RSAENH_CPExportKey(pKey->hProv, hCryptKey, 0, + PRIVATEKEYBLOB, 0, pbKey, &dwLen)) + { + blobIn.pbData = pbKey; + blobIn.cbData = dwLen; + + if (CryptProtectData(&blobIn, NULL, NULL, NULL, NULL, + dwFlags, &blobOut)) + { + RegSetValueExA(hKey, szValueName, 0, REG_BINARY, + blobOut.pbData, blobOut.cbData); + LocalFree(blobOut.pbData); + } + } + HeapFree(GetProcessHeap(), 0, pbKey); + } + } + release_handle(&handle_table, hCryptKey, RSAENH_MAGIC_KEY); + } +} + +/****************************************************************************** + * create_container_key [Internal] + * + * Creates the registry key for a key container's persistent storage. + * + * PARAMS + * pKeyContainer [I] Pointer to the key container + * sam [I] Desired registry access + * phKey [O] Returned key + */ +static BOOL create_container_key(KEYCONTAINER *pKeyContainer, REGSAM sam, HKEY *phKey) +{ + CHAR szRSABase[MAX_PATH]; + HKEY hRootKey; + + sprintf(szRSABase, RSAENH_REGKEY, pKeyContainer->szName); + + if (pKeyContainer->dwFlags & CRYPT_MACHINE_KEYSET) + hRootKey = HKEY_LOCAL_MACHINE; + else + hRootKey = HKEY_CURRENT_USER; + + /* @@ Wine registry key: HKLM\Software\Wine\Crypto\RSA */ + /* @@ Wine registry key: HKCU\Software\Wine\Crypto\RSA */ + return RegCreateKeyExA(hRootKey, szRSABase, 0, NULL, + REG_OPTION_NON_VOLATILE, sam, NULL, phKey, NULL) + == ERROR_SUCCESS; +} + +/****************************************************************************** + * open_container_key [Internal] + * + * Opens a key container's persistent storage for reading. + * + * PARAMS + * pszContainerName [I] Name of the container to be opened. May be the empty + * string if the parent key of all containers is to be + * opened. + * dwFlags [I] Flags indicating which keyset to be opened. + * phKey [O] Returned key + */ +static BOOL open_container_key(LPCSTR pszContainerName, DWORD dwFlags, HKEY *phKey) +{ + CHAR szRSABase[MAX_PATH]; + HKEY hRootKey; + + sprintf(szRSABase, RSAENH_REGKEY, pszContainerName); + + if (dwFlags & CRYPT_MACHINE_KEYSET) + hRootKey = HKEY_LOCAL_MACHINE; + else + hRootKey = HKEY_CURRENT_USER; + + /* @@ Wine registry key: HKLM\Software\Wine\Crypto\RSA */ + /* @@ Wine registry key: HKCU\Software\Wine\Crypto\RSA */ + return RegOpenKeyExA(hRootKey, szRSABase, 0, KEY_READ, phKey) == + ERROR_SUCCESS; +} + +/****************************************************************************** + * delete_container_key [Internal] + * + * Deletes a key container's persistent storage. + * + * PARAMS + * pszContainerName [I] Name of the container to be opened. + * dwFlags [I] Flags indicating which keyset to be opened. + */ +static BOOL delete_container_key(LPCSTR pszContainerName, DWORD dwFlags) +{ + CHAR szRegKey[MAX_PATH]; + + if (snprintf(szRegKey, MAX_PATH, RSAENH_REGKEY, pszContainerName) >= MAX_PATH) { + SetLastError(NTE_BAD_KEYSET_PARAM); + return FALSE; + } else { + HKEY hRootKey; + if (dwFlags & CRYPT_MACHINE_KEYSET) + hRootKey = HKEY_LOCAL_MACHINE; + else + hRootKey = HKEY_CURRENT_USER; + if (!RegDeleteKeyA(hRootKey, szRegKey)) { + SetLastError(ERROR_SUCCESS); + return TRUE; + } else { + SetLastError(NTE_BAD_KEYSET); + return FALSE; + } + } +} + +/****************************************************************************** + * store_key_container_keys [Internal] + * + * Stores key container's keys in a persistent location. + * + * PARAMS + * pKeyContainer [I] Pointer to the key container whose keys are to be saved + */ +static void store_key_container_keys(KEYCONTAINER *pKeyContainer) +{ + HKEY hKey; + DWORD dwFlags; + + /* On WinXP, persistent keys are stored in a file located at: + * $AppData$\\Microsoft\\Crypto\\RSA\\$SID$\\some_hex_string + */ + + if (pKeyContainer->dwFlags & CRYPT_MACHINE_KEYSET) + dwFlags = CRYPTPROTECT_LOCAL_MACHINE; + else + dwFlags = 0; + + if (create_container_key(pKeyContainer, KEY_WRITE, &hKey)) + { + store_key_pair(pKeyContainer->hKeyExchangeKeyPair, hKey, + "KeyExchangeKeyPair", dwFlags); + store_key_pair(pKeyContainer->hSignatureKeyPair, hKey, + "SignatureKeyPair", dwFlags); + RegCloseKey(hKey); + } +} + +/****************************************************************************** + * destroy_key_container [Internal] + * + * Destructor for key containers. + * + * PARAMS + * pObjectHdr [I] Pointer to the key container to be destroyed. + */ +static void destroy_key_container(OBJECTHDR *pObjectHdr) +{ + KEYCONTAINER *pKeyContainer = (KEYCONTAINER*)pObjectHdr; + + if (!(pKeyContainer->dwFlags & CRYPT_VERIFYCONTEXT)) + store_key_container_keys(pKeyContainer); + HeapFree( GetProcessHeap(), 0, pKeyContainer ); +} + +/****************************************************************************** + * new_key_container [Internal] + * + * Create a new key container. The personality (RSA Base, Strong or Enhanced CP) + * of the CSP is determined via the pVTable->pszProvName string. + * + * PARAMS + * pszContainerName [I] Name of the key container. + * pVTable [I] Callback functions and context info provided by the OS + * + * RETURNS + * Success: Handle to the new key container. + * Failure: INVALID_HANDLE_VALUE + */ +static HCRYPTPROV new_key_container(PCCH pszContainerName, DWORD dwFlags, const VTableProvStruc *pVTable) +{ + KEYCONTAINER *pKeyContainer; + HCRYPTPROV hKeyContainer; + + hKeyContainer = (HCRYPTPROV)new_object(&handle_table, sizeof(KEYCONTAINER), RSAENH_MAGIC_CONTAINER, + destroy_key_container, (OBJECTHDR**)&pKeyContainer); + if (hKeyContainer != (HCRYPTPROV)INVALID_HANDLE_VALUE) + { + lstrcpynA(pKeyContainer->szName, pszContainerName, MAX_PATH); + pKeyContainer->dwFlags = dwFlags; + pKeyContainer->dwEnumAlgsCtr = 0; + pKeyContainer->hKeyExchangeKeyPair = (HCRYPTKEY)INVALID_HANDLE_VALUE; + pKeyContainer->hSignatureKeyPair = (HCRYPTKEY)INVALID_HANDLE_VALUE; + if (pVTable && pVTable->pszProvName) { + lstrcpynA(pKeyContainer->szProvName, pVTable->pszProvName, MAX_PATH); + if (!strcmp(pVTable->pszProvName, MS_DEF_PROV_A)) { + pKeyContainer->dwPersonality = RSAENH_PERSONALITY_BASE; + } else if (!strcmp(pVTable->pszProvName, MS_ENHANCED_PROV_A)) { + pKeyContainer->dwPersonality = RSAENH_PERSONALITY_ENHANCED; + } else if (!strcmp(pVTable->pszProvName, MS_DEF_RSA_SCHANNEL_PROV_A)) { + pKeyContainer->dwPersonality = RSAENH_PERSONALITY_SCHANNEL; + } else { + pKeyContainer->dwPersonality = RSAENH_PERSONALITY_STRONG; + } + } + + /* The new key container has to be inserted into the CSP immediately + * after creation to be available for CPGetProvParam's PP_ENUMCONTAINERS. */ + if (!(dwFlags & CRYPT_VERIFYCONTEXT)) { + HKEY hKey; + + if (create_container_key(pKeyContainer, KEY_WRITE, &hKey)) + RegCloseKey(hKey); + } + } + + return hKeyContainer; +} + +/****************************************************************************** + * read_key_value [Internal] + * + * Reads a key pair value from the registry + * + * PARAMS + * hKeyContainer [I] Crypt provider to use to import the key + * hKey [I] Registry key from which to read the key pair + * szValueName [I] Registry value from which to read the key pair's value + * dwFlags [I] Flags for unprotecting the key + * phCryptKey [O] Returned key + */ +static BOOL read_key_value(HCRYPTPROV hKeyContainer, HKEY hKey, LPCSTR szValueName, DWORD dwFlags, HCRYPTKEY *phCryptKey) +{ + DWORD dwValueType, dwLen; + BYTE *pbKey; + DATA_BLOB blobIn, blobOut; + BOOL ret = FALSE; + + if (RegQueryValueExA(hKey, szValueName, 0, &dwValueType, NULL, &dwLen) == + ERROR_SUCCESS) + { + pbKey = HeapAlloc(GetProcessHeap(), 0, dwLen); + if (pbKey) + { + if (RegQueryValueExA(hKey, szValueName, 0, &dwValueType, pbKey, &dwLen) == + ERROR_SUCCESS) + { + blobIn.pbData = pbKey; + blobIn.cbData = dwLen; + + if (CryptUnprotectData(&blobIn, NULL, NULL, NULL, NULL, + dwFlags, &blobOut)) + { + ret = RSAENH_CPImportKey(hKeyContainer, blobOut.pbData, blobOut.cbData, 0, 0, + phCryptKey); + LocalFree(blobOut.pbData); + } + } + HeapFree(GetProcessHeap(), 0, pbKey); + } + } + return ret; +} + +/****************************************************************************** + * read_key_container [Internal] + * + * Tries to read the persistent state of the key container (mainly the signature + * and key exchange private keys) given by pszContainerName. + * + * PARAMS + * pszContainerName [I] Name of the key container to read from the registry + * pVTable [I] Pointer to context data provided by the operating system + * + * RETURNS + * Success: Handle to the key container read from the registry + * Failure: INVALID_HANDLE_VALUE + */ +static HCRYPTPROV read_key_container(PCHAR pszContainerName, DWORD dwFlags, const VTableProvStruc *pVTable) +{ + HKEY hKey; + KEYCONTAINER *pKeyContainer; + HCRYPTPROV hKeyContainer; + HCRYPTKEY hCryptKey; + + if (!open_container_key(pszContainerName, dwFlags, &hKey)) + { + SetLastError(NTE_BAD_KEYSET); + return (HCRYPTPROV)INVALID_HANDLE_VALUE; + } + + hKeyContainer = new_key_container(pszContainerName, dwFlags, pVTable); + if (hKeyContainer != (HCRYPTPROV)INVALID_HANDLE_VALUE) + { + DWORD dwProtectFlags = (dwFlags & CRYPT_MACHINE_KEYSET) ? + CRYPTPROTECT_LOCAL_MACHINE : 0; + + if (!lookup_handle(&handle_table, hKeyContainer, RSAENH_MAGIC_CONTAINER, + (OBJECTHDR**)&pKeyContainer)) + return (HCRYPTPROV)INVALID_HANDLE_VALUE; + + if (read_key_value(hKeyContainer, hKey, "KeyExchangeKeyPair", + dwProtectFlags, &hCryptKey)) + pKeyContainer->hKeyExchangeKeyPair = hCryptKey; + if (read_key_value(hKeyContainer, hKey, "SignatureKeyPair", + dwProtectFlags, &hCryptKey)) + pKeyContainer->hSignatureKeyPair = hCryptKey; + } + + return hKeyContainer; +} + +/****************************************************************************** + * build_hash_signature [Internal] + * + * Builds a padded version of a hash to match the length of the RSA key modulus. + * + * PARAMS + * pbSignature [O] The padded hash object is stored here. + * dwLen [I] Length of the pbSignature buffer. + * aiAlgid [I] Algorithm identifier of the hash to be padded. + * abHashValue [I] The value of the hash object. + * dwHashLen [I] Length of the hash value. + * dwFlags [I] Selection of padding algorithm. + * + * RETURNS + * Success: TRUE + * Failure: FALSE (NTE_BAD_ALGID) + */ +static BOOL build_hash_signature(BYTE *pbSignature, DWORD dwLen, ALG_ID aiAlgid, + CONST BYTE *abHashValue, DWORD dwHashLen, DWORD dwFlags) +{ + /* These prefixes are meant to be concatenated with hash values of the + * respective kind to form a PKCS #7 DigestInfo. */ + static const struct tagOIDDescriptor { + ALG_ID aiAlgid; + DWORD dwLen; + CONST BYTE abOID[18]; + } aOIDDescriptor[5] = { + { CALG_MD2, 18, { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x02, 0x02, 0x05, 0x00, 0x04, 0x10 } }, + { CALG_MD4, 18, { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x02, 0x04, 0x05, 0x00, 0x04, 0x10 } }, + { CALG_MD5, 18, { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 } }, + { CALG_SHA, 15, { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, + 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 } }, + { 0, 0, {} } + }; + DWORD dwIdxOID, i, j; + + for (dwIdxOID = 0; aOIDDescriptor[dwIdxOID].aiAlgid; dwIdxOID++) { + if (aOIDDescriptor[dwIdxOID].aiAlgid == aiAlgid) break; + } + + if (!aOIDDescriptor[dwIdxOID].aiAlgid) { + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + + /* Build the padded signature */ + if (dwFlags & CRYPT_X931_FORMAT) { + pbSignature[0] = 0x6b; + for (i=1; i < dwLen - dwHashLen - 3; i++) { + pbSignature[i] = 0xbb; + } + pbSignature[i++] = 0xba; + for (j=0; j < dwHashLen; j++, i++) { + pbSignature[i] = abHashValue[j]; + } + pbSignature[i++] = 0x33; + pbSignature[i++] = 0xcc; + } else { + pbSignature[0] = 0x00; + pbSignature[1] = 0x01; + if (dwFlags & CRYPT_NOHASHOID) { + for (i=2; i < dwLen - 1 - dwHashLen; i++) { + pbSignature[i] = 0xff; + } + pbSignature[i++] = 0x00; + } else { + for (i=2; i < dwLen - 1 - aOIDDescriptor[dwIdxOID].dwLen - dwHashLen; i++) { + pbSignature[i] = 0xff; + } + pbSignature[i++] = 0x00; + for (j=0; j < aOIDDescriptor[dwIdxOID].dwLen; j++) { + pbSignature[i++] = aOIDDescriptor[dwIdxOID].abOID[j]; + } + } + for (j=0; j < dwHashLen; j++) { + pbSignature[i++] = abHashValue[j]; + } + } + + return TRUE; +} + +/****************************************************************************** + * tls1_p [Internal] + * + * This is an implementation of the 'P_hash' helper function for TLS1's PRF. + * It is used exclusively by tls1_prf. For details see RFC 2246, chapter 5. + * The pseudo random stream generated by this function is exclusive or'ed with + * the data in pbBuffer. + * + * PARAMS + * hHMAC [I] HMAC object, which will be used in pseudo random generation + * pblobSeed [I] Seed value + * pbBuffer [I/O] Pseudo random stream will be xor'ed to the provided data + * dwBufferLen [I] Number of pseudo random bytes desired + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +static BOOL tls1_p(HCRYPTHASH hHMAC, CONST PCRYPT_DATA_BLOB pblobSeed, PBYTE pbBuffer, DWORD dwBufferLen) +{ + CRYPTHASH *pHMAC; + BYTE abAi[RSAENH_MAX_HASH_SIZE]; + DWORD i = 0; + + if (!lookup_handle(&handle_table, hHMAC, RSAENH_MAGIC_HASH, (OBJECTHDR**)&pHMAC)) { + SetLastError(NTE_BAD_HASH); + return FALSE; + } + + /* compute A_1 = HMAC(seed) */ + init_hash(pHMAC); + update_hash(pHMAC, pblobSeed->pbData, pblobSeed->cbData); + finalize_hash(pHMAC); + memcpy(abAi, pHMAC->abHashValue, pHMAC->dwHashSize); + + do { + /* compute HMAC(A_i + seed) */ + init_hash(pHMAC); + update_hash(pHMAC, abAi, pHMAC->dwHashSize); + update_hash(pHMAC, pblobSeed->pbData, pblobSeed->cbData); + finalize_hash(pHMAC); + + /* pseudo random stream := CONCAT_{i=1..n} ( HMAC(A_i + seed) ) */ + do { + if (i >= dwBufferLen) break; + pbBuffer[i] ^= pHMAC->abHashValue[i % pHMAC->dwHashSize]; + i++; + } while (i % pHMAC->dwHashSize); + + /* compute A_{i+1} = HMAC(A_i) */ + init_hash(pHMAC); + update_hash(pHMAC, abAi, pHMAC->dwHashSize); + finalize_hash(pHMAC); + memcpy(abAi, pHMAC->abHashValue, pHMAC->dwHashSize); + } while (i < dwBufferLen); + + return TRUE; +} + +/****************************************************************************** + * tls1_prf [Internal] + * + * TLS1 pseudo random function as specified in RFC 2246, chapter 5 + * + * PARAMS + * hProv [I] Key container used to compute the pseudo random stream + * hSecret [I] Key that holds the (pre-)master secret + * pblobLabel [I] Descriptive label + * pblobSeed [I] Seed value + * pbBuffer [O] Pseudo random numbers will be stored here + * dwBufferLen [I] Number of pseudo random bytes desired + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +static BOOL tls1_prf(HCRYPTPROV hProv, HCRYPTPROV hSecret, CONST PCRYPT_DATA_BLOB pblobLabel, + CONST PCRYPT_DATA_BLOB pblobSeed, PBYTE pbBuffer, DWORD dwBufferLen) +{ + HMAC_INFO hmacInfo = { 0, NULL, 0, NULL, 0 }; + HCRYPTHASH hHMAC = (HCRYPTHASH)INVALID_HANDLE_VALUE; + HCRYPTKEY hHalfSecret = (HCRYPTKEY)INVALID_HANDLE_VALUE; + CRYPTKEY *pHalfSecret, *pSecret; + DWORD dwHalfSecretLen; + BOOL result = FALSE; + CRYPT_DATA_BLOB blobLabelSeed; + + TRACE("(hProv=%08lx, hSecret=%08lx, pblobLabel=%p, pblobSeed=%p, pbBuffer=%p, dwBufferLen=%d)\n", + hProv, hSecret, pblobLabel, pblobSeed, pbBuffer, dwBufferLen); + + if (!lookup_handle(&handle_table, hSecret, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pSecret)) { + SetLastError(NTE_FAIL); + return FALSE; + } + + dwHalfSecretLen = (pSecret->dwKeyLen+1)/2; + + /* concatenation of the label and the seed */ + if (!concat_data_blobs(&blobLabelSeed, pblobLabel, pblobSeed)) goto exit; + + /* zero out the buffer, since two random streams will be xor'ed into it. */ + memset(pbBuffer, 0, dwBufferLen); + + /* build a 'fake' key, to hold the secret. CALG_SSL2_MASTER is used since it provides + * the biggest range of valid key lengths. */ + hHalfSecret = new_key(hProv, CALG_SSL2_MASTER, MAKELONG(0,dwHalfSecretLen*8), &pHalfSecret); + if (hHalfSecret == (HCRYPTKEY)INVALID_HANDLE_VALUE) goto exit; + + /* Derive an HMAC_MD5 hash and call the helper function. */ + memcpy(pHalfSecret->abKeyValue, pSecret->abKeyValue, dwHalfSecretLen); + if (!RSAENH_CPCreateHash(hProv, CALG_HMAC, hHalfSecret, 0, &hHMAC)) goto exit; + hmacInfo.HashAlgid = CALG_MD5; + if (!RSAENH_CPSetHashParam(hProv, hHMAC, HP_HMAC_INFO, (BYTE*)&hmacInfo, 0)) goto exit; + if (!tls1_p(hHMAC, &blobLabelSeed, pbBuffer, dwBufferLen)) goto exit; + + /* Reconfigure to HMAC_SHA hash and call helper function again. */ + memcpy(pHalfSecret->abKeyValue, pSecret->abKeyValue + (pSecret->dwKeyLen/2), dwHalfSecretLen); + hmacInfo.HashAlgid = CALG_SHA; + if (!RSAENH_CPSetHashParam(hProv, hHMAC, HP_HMAC_INFO, (BYTE*)&hmacInfo, 0)) goto exit; + if (!tls1_p(hHMAC, &blobLabelSeed, pbBuffer, dwBufferLen)) goto exit; + + result = TRUE; +exit: + release_handle(&handle_table, hHalfSecret, RSAENH_MAGIC_KEY); + if (hHMAC != (HCRYPTHASH)INVALID_HANDLE_VALUE) RSAENH_CPDestroyHash(hProv, hHMAC); + free_data_blob(&blobLabelSeed); + return result; +} + +/****************************************************************************** + * pad_data [Internal] + * + * Helper function for data padding according to PKCS1 #2 + * + * PARAMS + * abData [I] The data to be padded + * dwDataLen [I] Length of the data + * abBuffer [O] Padded data will be stored here + * dwBufferLen [I] Length of the buffer (also length of padded data) + * dwFlags [I] Padding format (CRYPT_SSL2_FALLBACK) + * + * RETURN + * Success: TRUE + * Failure: FALSE (NTE_BAD_LEN, too much data to pad) + */ +static BOOL pad_data(CONST BYTE *abData, DWORD dwDataLen, BYTE *abBuffer, DWORD dwBufferLen, + DWORD dwFlags) +{ + DWORD i; + + /* Ensure there is enough space for PKCS1 #2 padding */ + if (dwDataLen > dwBufferLen-11) { + SetLastError(NTE_BAD_LEN); + return FALSE; + } + + memmove(abBuffer + dwBufferLen - dwDataLen, abData, dwDataLen); + + abBuffer[0] = 0x00; + abBuffer[1] = RSAENH_PKC_BLOCKTYPE; + for (i=2; i < dwBufferLen - dwDataLen - 1; i++) + do gen_rand_impl(&abBuffer[i], 1); while (!abBuffer[i]); + if (dwFlags & CRYPT_SSL2_FALLBACK) + for (i-=8; i < dwBufferLen - dwDataLen - 1; i++) + abBuffer[i] = 0x03; + abBuffer[i] = 0x00; + + return TRUE; +} + +/****************************************************************************** + * unpad_data [Internal] + * + * Remove the PKCS1 padding from RSA decrypted data + * + * PARAMS + * abData [I] The padded data + * dwDataLen [I] Length of the padded data + * abBuffer [O] Data without padding will be stored here + * dwBufferLen [I/O] I: Length of the buffer, O: Length of unpadded data + * dwFlags [I] Currently none defined + * + * RETURNS + * Success: TRUE + * Failure: FALSE, (NTE_BAD_DATA, no valid PKCS1 padding or buffer too small) + */ +static BOOL unpad_data(CONST BYTE *abData, DWORD dwDataLen, BYTE *abBuffer, DWORD *dwBufferLen, + DWORD dwFlags) +{ + DWORD i; + + for (i=2; iaiAlgid) != ALG_TYPE_BLOCK)) { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + if ((Algid == CALG_SCHANNEL_MASTER_HASH || Algid == CALG_TLS1PRF) && + (pCryptKey->aiAlgid != CALG_TLS1_MASTER)) + { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + if ((Algid == CALG_TLS1PRF) && (pCryptKey->dwState != RSAENH_KEYSTATE_MASTERKEY)) { + SetLastError(NTE_BAD_KEY_STATE); + return FALSE; + } + } + + *phHash = (HCRYPTHASH)new_object(&handle_table, sizeof(CRYPTHASH), RSAENH_MAGIC_HASH, + destroy_hash, (OBJECTHDR**)&pCryptHash); + if (!pCryptHash) return FALSE; + + pCryptHash->aiAlgid = Algid; + pCryptHash->hKey = hKey; + pCryptHash->hProv = hProv; + pCryptHash->dwState = RSAENH_HASHSTATE_HASHING; + pCryptHash->pHMACInfo = (PHMAC_INFO)NULL; + pCryptHash->dwHashSize = peaAlgidInfo->dwDefaultLen >> 3; + init_data_blob(&pCryptHash->tpPRFParams.blobLabel); + init_data_blob(&pCryptHash->tpPRFParams.blobSeed); + + if (Algid == CALG_SCHANNEL_MASTER_HASH) { + static const char keyex[] = "key expansion"; + BYTE key_expansion[sizeof keyex]; + CRYPT_DATA_BLOB blobRandom, blobKeyExpansion = { 13, key_expansion }; + + memcpy( key_expansion, keyex, sizeof keyex ); + + if (pCryptKey->dwState != RSAENH_KEYSTATE_MASTERKEY) { + static const char msec[] = "master secret"; + BYTE master_secret[sizeof msec]; + CRYPT_DATA_BLOB blobLabel = { 13, master_secret }; + BYTE abKeyValue[48]; + + memcpy( master_secret, msec, sizeof msec ); + + /* See RFC 2246, chapter 8.1 */ + if (!concat_data_blobs(&blobRandom, + &pCryptKey->siSChannelInfo.blobClientRandom, + &pCryptKey->siSChannelInfo.blobServerRandom)) + { + return FALSE; + } + tls1_prf(hProv, hKey, &blobLabel, &blobRandom, abKeyValue, 48); + pCryptKey->dwState = RSAENH_KEYSTATE_MASTERKEY; + memcpy(pCryptKey->abKeyValue, abKeyValue, 48); + free_data_blob(&blobRandom); + } + + /* See RFC 2246, chapter 6.3 */ + if (!concat_data_blobs(&blobRandom, + &pCryptKey->siSChannelInfo.blobServerRandom, + &pCryptKey->siSChannelInfo.blobClientRandom)) + { + return FALSE; + } + tls1_prf(hProv, hKey, &blobKeyExpansion, &blobRandom, pCryptHash->abHashValue, + RSAENH_MAX_HASH_SIZE); + free_data_blob(&blobRandom); + } + + return init_hash(pCryptHash); +} + +/****************************************************************************** + * CPDestroyHash (RSAENH.@) + * + * Releases the handle to a hash object. The object is destroyed if it's reference + * count reaches zero. + * + * PARAMS + * hProv [I] Handle to the key container to which the hash object belongs. + * hHash [I] Handle to the hash object to be released. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI RSAENH_CPDestroyHash(HCRYPTPROV hProv, HCRYPTHASH hHash) +{ + TRACE("(hProv=%08lx, hHash=%08lx)\n", hProv, hHash); + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (!release_handle(&handle_table, hHash, RSAENH_MAGIC_HASH)) + { + SetLastError(NTE_BAD_HASH); + return FALSE; + } + + return TRUE; +} + +/****************************************************************************** + * CPDestroyKey (RSAENH.@) + * + * Releases the handle to a key object. The object is destroyed if it's reference + * count reaches zero. + * + * PARAMS + * hProv [I] Handle to the key container to which the key object belongs. + * hKey [I] Handle to the key object to be released. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI RSAENH_CPDestroyKey(HCRYPTPROV hProv, HCRYPTKEY hKey) +{ + TRACE("(hProv=%08lx, hKey=%08lx)\n", hProv, hKey); + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (!release_handle(&handle_table, hKey, RSAENH_MAGIC_KEY)) + { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + return TRUE; +} + +/****************************************************************************** + * CPDuplicateHash (RSAENH.@) + * + * Clones a hash object including it's current state. + * + * PARAMS + * hUID [I] Handle to the key container the hash belongs to. + * hHash [I] Handle to the hash object to be cloned. + * pdwReserved [I] Reserved. Must be NULL. + * dwFlags [I] No flags are currently defined. Must be 0. + * phHash [O] Handle to the cloned hash object. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + */ +BOOL WINAPI RSAENH_CPDuplicateHash(HCRYPTPROV hUID, HCRYPTHASH hHash, DWORD *pdwReserved, + DWORD dwFlags, HCRYPTHASH *phHash) +{ + CRYPTHASH *pSrcHash, *pDestHash; + + TRACE("(hUID=%08lx, hHash=%08lx, pdwReserved=%p, dwFlags=%08x, phHash=%p)\n", hUID, hHash, + pdwReserved, dwFlags, phHash); + + if (!is_valid_handle(&handle_table, hUID, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (!lookup_handle(&handle_table, hHash, RSAENH_MAGIC_HASH, (OBJECTHDR**)&pSrcHash)) + { + SetLastError(NTE_BAD_HASH); + return FALSE; + } + + if (!phHash || pdwReserved || dwFlags) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + *phHash = (HCRYPTHASH)new_object(&handle_table, sizeof(CRYPTHASH), RSAENH_MAGIC_HASH, + destroy_hash, (OBJECTHDR**)&pDestHash); + if (*phHash != (HCRYPTHASH)INVALID_HANDLE_VALUE) + { + memcpy(pDestHash, pSrcHash, sizeof(CRYPTHASH)); + duplicate_hash_impl(pSrcHash->aiAlgid, &pSrcHash->context, &pDestHash->context); + copy_hmac_info(&pDestHash->pHMACInfo, pSrcHash->pHMACInfo); + copy_data_blob(&pDestHash->tpPRFParams.blobLabel, &pSrcHash->tpPRFParams.blobLabel); + copy_data_blob(&pDestHash->tpPRFParams.blobSeed, &pSrcHash->tpPRFParams.blobSeed); + } + + return *phHash != (HCRYPTHASH)INVALID_HANDLE_VALUE; +} + +/****************************************************************************** + * CPDuplicateKey (RSAENH.@) + * + * Clones a key object including it's current state. + * + * PARAMS + * hUID [I] Handle to the key container the hash belongs to. + * hKey [I] Handle to the key object to be cloned. + * pdwReserved [I] Reserved. Must be NULL. + * dwFlags [I] No flags are currently defined. Must be 0. + * phHash [O] Handle to the cloned key object. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + */ +BOOL WINAPI RSAENH_CPDuplicateKey(HCRYPTPROV hUID, HCRYPTKEY hKey, DWORD *pdwReserved, + DWORD dwFlags, HCRYPTKEY *phKey) +{ + CRYPTKEY *pSrcKey, *pDestKey; + + TRACE("(hUID=%08lx, hKey=%08lx, pdwReserved=%p, dwFlags=%08x, phKey=%p)\n", hUID, hKey, + pdwReserved, dwFlags, phKey); + + if (!is_valid_handle(&handle_table, hUID, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pSrcKey)) + { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + if (!phKey || pdwReserved || dwFlags) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + *phKey = (HCRYPTKEY)new_object(&handle_table, sizeof(CRYPTKEY), RSAENH_MAGIC_KEY, destroy_key, + (OBJECTHDR**)&pDestKey); + if (*phKey != (HCRYPTKEY)INVALID_HANDLE_VALUE) + { + memcpy(pDestKey, pSrcKey, sizeof(CRYPTKEY)); + copy_data_blob(&pDestKey->siSChannelInfo.blobServerRandom, + &pSrcKey->siSChannelInfo.blobServerRandom); + copy_data_blob(&pDestKey->siSChannelInfo.blobClientRandom, + &pSrcKey->siSChannelInfo.blobClientRandom); + duplicate_key_impl(pSrcKey->aiAlgid, &pSrcKey->context, &pDestKey->context); + return TRUE; + } + else + { + return FALSE; + } +} + +/****************************************************************************** + * CPEncrypt (RSAENH.@) + * + * Encrypt data. + * + * PARAMS + * hProv [I] The key container hKey and hHash belong to. + * hKey [I] The key used to encrypt the data. + * hHash [I] An optional hash object for parallel hashing. See notes. + * Final [I] Indicates if this is the last block of data to encrypt. + * dwFlags [I] Currently no flags defined. Must be zero. + * pbData [I/O] Pointer to the data to encrypt. Encrypted data will also be stored there. + * pdwDataLen [I/O] I: Length of data to encrypt, O: Length of encrypted data. + * dwBufLen [I] Size of the buffer at pbData. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + * + * NOTES + * If a hash object handle is provided in hHash, it will be updated with the plaintext. + * This is useful for message signatures. + * + * This function uses the standard WINAPI protocol for querying data of dynamic length. + */ +BOOL WINAPI RSAENH_CPEncrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, + DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen) +{ + CRYPTKEY *pCryptKey; + BYTE *in, out[RSAENH_MAX_BLOCK_SIZE], o[RSAENH_MAX_BLOCK_SIZE]; + DWORD dwEncryptedLen, i, j, k; + + TRACE("(hProv=%08lx, hKey=%08lx, hHash=%08lx, Final=%d, dwFlags=%08x, pbData=%p, " + "pdwDataLen=%p, dwBufLen=%d)\n", hProv, hKey, hHash, Final, dwFlags, pbData, pdwDataLen, + dwBufLen); + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (dwFlags) + { + SetLastError(NTE_BAD_FLAGS); + return FALSE; + } + + if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey)) + { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + if (pCryptKey->dwState == RSAENH_KEYSTATE_IDLE) + pCryptKey->dwState = RSAENH_KEYSTATE_ENCRYPTING; + + if (pCryptKey->dwState != RSAENH_KEYSTATE_ENCRYPTING) + { + SetLastError(NTE_BAD_DATA); + return FALSE; + } + + if (is_valid_handle(&handle_table, hHash, RSAENH_MAGIC_HASH)) { + if (!RSAENH_CPHashData(hProv, hHash, pbData, *pdwDataLen, 0)) return FALSE; + } + + if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_BLOCK) { + if (!Final && (*pdwDataLen % pCryptKey->dwBlockLen)) { + SetLastError(NTE_BAD_DATA); + return FALSE; + } + + dwEncryptedLen = (*pdwDataLen/pCryptKey->dwBlockLen+(Final?1:0))*pCryptKey->dwBlockLen; + + if (pbData == NULL) { + *pdwDataLen = dwEncryptedLen; + return TRUE; + } + else if (dwEncryptedLen > dwBufLen) { + *pdwDataLen = dwEncryptedLen; + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + + /* Pad final block with length bytes */ + for (i=*pdwDataLen; idwBlockLen, in+=pCryptKey->dwBlockLen) { + switch (pCryptKey->dwMode) { + case CRYPT_MODE_ECB: + encrypt_block_impl(pCryptKey->aiAlgid, 0, &pCryptKey->context, in, out, + RSAENH_ENCRYPT); + break; + + case CRYPT_MODE_CBC: + for (j=0; jdwBlockLen; j++) in[j] ^= pCryptKey->abChainVector[j]; + encrypt_block_impl(pCryptKey->aiAlgid, 0, &pCryptKey->context, in, out, + RSAENH_ENCRYPT); + memcpy(pCryptKey->abChainVector, out, pCryptKey->dwBlockLen); + break; + + case CRYPT_MODE_CFB: + for (j=0; jdwBlockLen; j++) { + encrypt_block_impl(pCryptKey->aiAlgid, 0, &pCryptKey->context, + pCryptKey->abChainVector, o, RSAENH_ENCRYPT); + out[j] = in[j] ^ o[0]; + for (k=0; kdwBlockLen-1; k++) + pCryptKey->abChainVector[k] = pCryptKey->abChainVector[k+1]; + pCryptKey->abChainVector[k] = out[j]; + } + break; + + default: + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + memcpy(in, out, pCryptKey->dwBlockLen); + } + } else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_STREAM) { + if (pbData == NULL) { + *pdwDataLen = dwBufLen; + return TRUE; + } + encrypt_stream_impl(pCryptKey->aiAlgid, &pCryptKey->context, pbData, *pdwDataLen); + } else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_RSA) { + if (pCryptKey->aiAlgid == CALG_RSA_SIGN) { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + if (!pbData) { + *pdwDataLen = pCryptKey->dwBlockLen; + return TRUE; + } + if (dwBufLen < pCryptKey->dwBlockLen) { + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + if (!pad_data(pbData, *pdwDataLen, pbData, pCryptKey->dwBlockLen, dwFlags)) return FALSE; + encrypt_block_impl(pCryptKey->aiAlgid, PK_PUBLIC, &pCryptKey->context, pbData, pbData, RSAENH_ENCRYPT); + *pdwDataLen = pCryptKey->dwBlockLen; + Final = TRUE; + } else { + SetLastError(NTE_BAD_TYPE); + return FALSE; + } + + if (Final) setup_key(pCryptKey); + + return TRUE; +} + +/****************************************************************************** + * CPDecrypt (RSAENH.@) + * + * Decrypt data. + * + * PARAMS + * hProv [I] The key container hKey and hHash belong to. + * hKey [I] The key used to decrypt the data. + * hHash [I] An optional hash object for parallel hashing. See notes. + * Final [I] Indicates if this is the last block of data to decrypt. + * dwFlags [I] Currently no flags defined. Must be zero. + * pbData [I/O] Pointer to the data to decrypt. Plaintext will also be stored there. + * pdwDataLen [I/O] I: Length of ciphertext, O: Length of plaintext. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + * + * NOTES + * If a hash object handle is provided in hHash, it will be updated with the plaintext. + * This is useful for message signatures. + * + * This function uses the standard WINAPI protocol for querying data of dynamic length. + */ +BOOL WINAPI RSAENH_CPDecrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, + DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen) +{ + CRYPTKEY *pCryptKey; + BYTE *in, out[RSAENH_MAX_BLOCK_SIZE], o[RSAENH_MAX_BLOCK_SIZE]; + DWORD i, j, k; + DWORD dwMax; + + TRACE("(hProv=%08lx, hKey=%08lx, hHash=%08lx, Final=%d, dwFlags=%08x, pbData=%p, " + "pdwDataLen=%p)\n", hProv, hKey, hHash, Final, dwFlags, pbData, pdwDataLen); + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (dwFlags) + { + SetLastError(NTE_BAD_FLAGS); + return FALSE; + } + + if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey)) + { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + if (pCryptKey->dwState == RSAENH_KEYSTATE_IDLE) + pCryptKey->dwState = RSAENH_KEYSTATE_DECRYPTING; + + if (pCryptKey->dwState != RSAENH_KEYSTATE_DECRYPTING) + { + SetLastError(NTE_BAD_DATA); + return FALSE; + } + + dwMax=*pdwDataLen; + + if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_BLOCK) { + for (i=0, in=pbData; i<*pdwDataLen; i+=pCryptKey->dwBlockLen, in+=pCryptKey->dwBlockLen) { + switch (pCryptKey->dwMode) { + case CRYPT_MODE_ECB: + encrypt_block_impl(pCryptKey->aiAlgid, 0, &pCryptKey->context, in, out, + RSAENH_DECRYPT); + break; + + case CRYPT_MODE_CBC: + encrypt_block_impl(pCryptKey->aiAlgid, 0, &pCryptKey->context, in, out, + RSAENH_DECRYPT); + for (j=0; jdwBlockLen; j++) out[j] ^= pCryptKey->abChainVector[j]; + memcpy(pCryptKey->abChainVector, in, pCryptKey->dwBlockLen); + break; + + case CRYPT_MODE_CFB: + for (j=0; jdwBlockLen; j++) { + encrypt_block_impl(pCryptKey->aiAlgid, 0, &pCryptKey->context, + pCryptKey->abChainVector, o, RSAENH_ENCRYPT); + out[j] = in[j] ^ o[0]; + for (k=0; kdwBlockLen-1; k++) + pCryptKey->abChainVector[k] = pCryptKey->abChainVector[k+1]; + pCryptKey->abChainVector[k] = in[j]; + } + break; + + default: + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + memcpy(in, out, pCryptKey->dwBlockLen); + } + if (Final) { + if (pbData[*pdwDataLen-1] && + pbData[*pdwDataLen-1] <= pCryptKey->dwBlockLen && + pbData[*pdwDataLen-1] < *pdwDataLen) { + BOOL padOkay = TRUE; + + /* check that every bad byte has the same value */ + for (i = 1; padOkay && i < pbData[*pdwDataLen-1]; i++) + if (pbData[*pdwDataLen - i - 1] != pbData[*pdwDataLen - 1]) + padOkay = FALSE; + if (padOkay) + *pdwDataLen -= pbData[*pdwDataLen-1]; + else { + SetLastError(NTE_BAD_DATA); + return FALSE; + } + } + else { + SetLastError(NTE_BAD_DATA); + return FALSE; + } + } + + } else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_STREAM) { + encrypt_stream_impl(pCryptKey->aiAlgid, &pCryptKey->context, pbData, *pdwDataLen); + } else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_RSA) { + if (pCryptKey->aiAlgid == CALG_RSA_SIGN) { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + encrypt_block_impl(pCryptKey->aiAlgid, PK_PRIVATE, &pCryptKey->context, pbData, pbData, RSAENH_DECRYPT); + if (!unpad_data(pbData, pCryptKey->dwBlockLen, pbData, pdwDataLen, dwFlags)) return FALSE; + Final = TRUE; + } else { + SetLastError(NTE_BAD_TYPE); + return FALSE; + } + + if (Final) setup_key(pCryptKey); + + if (is_valid_handle(&handle_table, hHash, RSAENH_MAGIC_HASH)) { + if (*pdwDataLen>dwMax || + !RSAENH_CPHashData(hProv, hHash, pbData, *pdwDataLen, 0)) return FALSE; + } + + return TRUE; +} + +/****************************************************************************** + * CPExportKey (RSAENH.@) + * + * Export a key into a binary large object (BLOB). + * + * PARAMS + * hProv [I] Key container from which a key is to be exported. + * hKey [I] Key to be exported. + * hPubKey [I] Key used to encrypt sensitive BLOB data. + * dwBlobType [I] SIMPLEBLOB, PUBLICKEYBLOB or PRIVATEKEYBLOB. + * dwFlags [I] Currently none defined. + * pbData [O] Pointer to a buffer where the BLOB will be written to. + * pdwDataLen [I/O] I: Size of buffer at pbData, O: Size of BLOB + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + */ +BOOL WINAPI RSAENH_CPExportKey(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTKEY hPubKey, + DWORD dwBlobType, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen) +{ + CRYPTKEY *pCryptKey, *pPubKey; + BLOBHEADER *pBlobHeader = (BLOBHEADER*)pbData; + RSAPUBKEY *pRSAPubKey = (RSAPUBKEY*)(pBlobHeader+1); + ALG_ID *pAlgid = (ALG_ID*)(pBlobHeader+1); + DWORD dwDataLen; + + TRACE("(hProv=%08lx, hKey=%08lx, hPubKey=%08lx, dwBlobType=%08x, dwFlags=%08x, pbData=%p," + "pdwDataLen=%p)\n", hProv, hKey, hPubKey, dwBlobType, dwFlags, pbData, pdwDataLen); + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey)) + { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + if (dwFlags & CRYPT_SSL2_FALLBACK) { + if (pCryptKey->aiAlgid != CALG_SSL2_MASTER) { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + } + + switch ((BYTE)dwBlobType) + { + case SIMPLEBLOB: + if (!lookup_handle(&handle_table, hPubKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pPubKey)){ + SetLastError(NTE_BAD_PUBLIC_KEY); /* FIXME: error_code? */ + return FALSE; + } + + if (!(GET_ALG_CLASS(pCryptKey->aiAlgid)&(ALG_CLASS_DATA_ENCRYPT|ALG_CLASS_MSG_ENCRYPT))) { + SetLastError(NTE_BAD_KEY); /* FIXME: error code? */ + return FALSE; + } + + dwDataLen = sizeof(BLOBHEADER) + sizeof(ALG_ID) + pPubKey->dwBlockLen; + if (pbData) { + if (*pdwDataLen < dwDataLen) { + SetLastError(ERROR_MORE_DATA); + *pdwDataLen = dwDataLen; + return FALSE; + } + + pBlobHeader->bType = SIMPLEBLOB; + pBlobHeader->bVersion = CUR_BLOB_VERSION; + pBlobHeader->reserved = 0; + pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid; + + *pAlgid = pPubKey->aiAlgid; + + if (!pad_data(pCryptKey->abKeyValue, pCryptKey->dwKeyLen, (BYTE*)(pAlgid+1), + pPubKey->dwBlockLen, dwFlags)) + { + return FALSE; + } + + encrypt_block_impl(pPubKey->aiAlgid, PK_PUBLIC, &pPubKey->context, (BYTE*)(pAlgid+1), + (BYTE*)(pAlgid+1), RSAENH_ENCRYPT); + } + *pdwDataLen = dwDataLen; + return TRUE; + + case PUBLICKEYBLOB: + if (is_valid_handle(&handle_table, hPubKey, RSAENH_MAGIC_KEY)) { + SetLastError(NTE_BAD_KEY); /* FIXME: error code? */ + return FALSE; + } + + if ((pCryptKey->aiAlgid != CALG_RSA_KEYX) && (pCryptKey->aiAlgid != CALG_RSA_SIGN)) { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + dwDataLen = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + pCryptKey->dwKeyLen; + if (pbData) { + if (*pdwDataLen < dwDataLen) { + SetLastError(ERROR_MORE_DATA); + *pdwDataLen = dwDataLen; + return FALSE; + } + + pBlobHeader->bType = PUBLICKEYBLOB; + pBlobHeader->bVersion = CUR_BLOB_VERSION; + pBlobHeader->reserved = 0; + pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid; + + pRSAPubKey->magic = RSAENH_MAGIC_RSA1; + pRSAPubKey->bitlen = pCryptKey->dwKeyLen << 3; + + export_public_key_impl((BYTE*)(pRSAPubKey+1), &pCryptKey->context, + pCryptKey->dwKeyLen, &pRSAPubKey->pubexp); + } + *pdwDataLen = dwDataLen; + return TRUE; + + case PRIVATEKEYBLOB: + if ((pCryptKey->aiAlgid != CALG_RSA_KEYX) && (pCryptKey->aiAlgid != CALG_RSA_SIGN)) { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + dwDataLen = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + + 2 * pCryptKey->dwKeyLen + 5 * ((pCryptKey->dwKeyLen + 1) >> 1); + if (pbData) { + if (*pdwDataLen < dwDataLen) { + SetLastError(ERROR_MORE_DATA); + *pdwDataLen = dwDataLen; + return FALSE; + } + + pBlobHeader->bType = PRIVATEKEYBLOB; + pBlobHeader->bVersion = CUR_BLOB_VERSION; + pBlobHeader->reserved = 0; + pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid; + + pRSAPubKey->magic = RSAENH_MAGIC_RSA2; + pRSAPubKey->bitlen = pCryptKey->dwKeyLen << 3; + + export_private_key_impl((BYTE*)(pRSAPubKey+1), &pCryptKey->context, + pCryptKey->dwKeyLen, &pRSAPubKey->pubexp); + } + *pdwDataLen = dwDataLen; + return TRUE; + + default: + SetLastError(NTE_BAD_TYPE); /* FIXME: error code? */ + return FALSE; + } +} + +/****************************************************************************** + * CPImportKey (RSAENH.@) + * + * Import a BLOB'ed key into a key container. + * + * PARAMS + * hProv [I] Key container into which the key is to be imported. + * pbData [I] Pointer to a buffer which holds the BLOB. + * dwDataLen [I] Length of data in buffer at pbData. + * hPubKey [I] Key used to decrypt sensitive BLOB data. + * dwFlags [I] Currently none defined. + * phKey [O] Handle to the imported key. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + */ +BOOL WINAPI RSAENH_CPImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen, + HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey) +{ + KEYCONTAINER *pKeyContainer; + CRYPTKEY *pCryptKey, *pPubKey; + CONST BLOBHEADER *pBlobHeader = (CONST BLOBHEADER*)pbData; + CONST RSAPUBKEY *pRSAPubKey = (CONST RSAPUBKEY*)(pBlobHeader+1); + CONST ALG_ID *pAlgid = (CONST ALG_ID*)(pBlobHeader+1); + CONST BYTE *pbKeyStream = (CONST BYTE*)(pAlgid + 1); + ALG_ID algID; + BYTE *pbDecrypted; + DWORD dwKeyLen; + BOOL ret; + + TRACE("(hProv=%08lx, pbData=%p, dwDataLen=%d, hPubKey=%08lx, dwFlags=%08x, phKey=%p)\n", + hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey); + + if (!lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER, + (OBJECTHDR**)&pKeyContainer)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (dwDataLen < sizeof(BLOBHEADER) || + pBlobHeader->bVersion != CUR_BLOB_VERSION || + pBlobHeader->reserved != 0) + { + SetLastError(NTE_BAD_DATA); + return FALSE; + } + + switch (pBlobHeader->bType) + { + case PRIVATEKEYBLOB: + if ((dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY)) || + (pRSAPubKey->magic != RSAENH_MAGIC_RSA2) || + (dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + + (2 * pRSAPubKey->bitlen >> 3) + (5 * ((pRSAPubKey->bitlen+8)>>4)))) + { + SetLastError(NTE_BAD_DATA); + return FALSE; + } + + *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, MAKELONG(0,pRSAPubKey->bitlen), &pCryptKey); + if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE; + setup_key(pCryptKey); + ret = import_private_key_impl((CONST BYTE*)(pRSAPubKey+1), &pCryptKey->context, + pRSAPubKey->bitlen/8, pRSAPubKey->pubexp); + if (ret) { + switch (pBlobHeader->aiKeyAlg) + { + case AT_SIGNATURE: + case CALG_RSA_SIGN: + TRACE("installing signing key\n"); + RSAENH_CPDestroyKey(hProv, pKeyContainer->hSignatureKeyPair); + copy_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY, + &pKeyContainer->hSignatureKeyPair); + break; + case AT_KEYEXCHANGE: + case CALG_RSA_KEYX: + TRACE("installing key exchange key\n"); + RSAENH_CPDestroyKey(hProv, pKeyContainer->hKeyExchangeKeyPair); + copy_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY, + &pKeyContainer->hKeyExchangeKeyPair); + break; + } + } + return ret; + + case PUBLICKEYBLOB: + if ((dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY)) || + (pRSAPubKey->magic != RSAENH_MAGIC_RSA1) || + (dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + (pRSAPubKey->bitlen >> 3))) + { + SetLastError(NTE_BAD_DATA); + return FALSE; + } + + /* Since this is a public key blob, only the public key is + * available, so only signature verification is possible. + */ + algID = pBlobHeader->aiKeyAlg; + *phKey = new_key(hProv, algID, MAKELONG(0,pRSAPubKey->bitlen), &pCryptKey); + if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE; + setup_key(pCryptKey); + ret = import_public_key_impl((CONST BYTE*)(pRSAPubKey+1), &pCryptKey->context, + pRSAPubKey->bitlen >> 3, pRSAPubKey->pubexp); + if (ret) { + switch (pBlobHeader->aiKeyAlg) + { + case AT_KEYEXCHANGE: + case CALG_RSA_KEYX: + TRACE("installing public key\n"); + RSAENH_CPDestroyKey(hProv, pKeyContainer->hKeyExchangeKeyPair); + copy_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY, + &pKeyContainer->hKeyExchangeKeyPair); + break; + } + } + return ret; + + case SIMPLEBLOB: + if (!lookup_handle(&handle_table, hPubKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pPubKey) || + pPubKey->aiAlgid != CALG_RSA_KEYX) + { + SetLastError(NTE_BAD_PUBLIC_KEY); /* FIXME: error code? */ + return FALSE; + } + + if (dwDataLen < sizeof(BLOBHEADER)+sizeof(ALG_ID)+pPubKey->dwBlockLen) + { + SetLastError(NTE_BAD_DATA); /* FIXME: error code */ + return FALSE; + } + + pbDecrypted = HeapAlloc(GetProcessHeap(), 0, pPubKey->dwBlockLen); + if (!pbDecrypted) return FALSE; + encrypt_block_impl(pPubKey->aiAlgid, PK_PRIVATE, &pPubKey->context, pbKeyStream, pbDecrypted, + RSAENH_DECRYPT); + + dwKeyLen = RSAENH_MAX_KEY_SIZE; + if (!unpad_data(pbDecrypted, pPubKey->dwBlockLen, pbDecrypted, &dwKeyLen, dwFlags)) { + HeapFree(GetProcessHeap(), 0, pbDecrypted); + return FALSE; + } + + *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, dwKeyLen<<19, &pCryptKey); + if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) + { + HeapFree(GetProcessHeap(), 0, pbDecrypted); + return FALSE; + } + memcpy(pCryptKey->abKeyValue, pbDecrypted, dwKeyLen); + HeapFree(GetProcessHeap(), 0, pbDecrypted); + setup_key(pCryptKey); + return TRUE; + + default: + SetLastError(NTE_BAD_TYPE); /* FIXME: error code? */ + return FALSE; + } +} + +/****************************************************************************** + * CPGenKey (RSAENH.@) + * + * Generate a key in the key container + * + * PARAMS + * hProv [I] Key container for which a key is to be generated. + * Algid [I] Crypto algorithm identifier for the key to be generated. + * dwFlags [I] Upper 16 bits: Binary length of key. Lower 16 bits: Flags. See Notes + * phKey [O] Handle to the generated key. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + * + * FIXME + * Flags currently not considered. + * + * NOTES + * Private key-exchange- and signature-keys can be generated with Algid AT_KEYEXCHANGE + * and AT_SIGNATURE values. + */ +BOOL WINAPI RSAENH_CPGenKey(HCRYPTPROV hProv, ALG_ID Algid, DWORD dwFlags, HCRYPTKEY *phKey) +{ + KEYCONTAINER *pKeyContainer; + CRYPTKEY *pCryptKey; + + TRACE("(hProv=%08lx, aiAlgid=%d, dwFlags=%08x, phKey=%p)\n", hProv, Algid, dwFlags, phKey); + + if (!lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER, + (OBJECTHDR**)&pKeyContainer)) + { + /* MSDN: hProv not containing valid context handle */ + SetLastError(NTE_BAD_UID); + return FALSE; + } + + switch (Algid) + { + case AT_SIGNATURE: + case CALG_RSA_SIGN: + *phKey = new_key(hProv, CALG_RSA_SIGN, dwFlags, &pCryptKey); + if (pCryptKey) { + new_key_impl(pCryptKey->aiAlgid, &pCryptKey->context, pCryptKey->dwKeyLen); + setup_key(pCryptKey); + if (Algid == AT_SIGNATURE) { + RSAENH_CPDestroyKey(hProv, pKeyContainer->hSignatureKeyPair); + copy_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY, + &pKeyContainer->hSignatureKeyPair); + } + } + break; + + case AT_KEYEXCHANGE: + case CALG_RSA_KEYX: + *phKey = new_key(hProv, CALG_RSA_KEYX, dwFlags, &pCryptKey); + if (pCryptKey) { + new_key_impl(pCryptKey->aiAlgid, &pCryptKey->context, pCryptKey->dwKeyLen); + setup_key(pCryptKey); + if (Algid == AT_KEYEXCHANGE) { + RSAENH_CPDestroyKey(hProv, pKeyContainer->hKeyExchangeKeyPair); + copy_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY, + &pKeyContainer->hKeyExchangeKeyPair); + } + } + break; + + case CALG_RC2: + case CALG_RC4: + case CALG_DES: + case CALG_3DES_112: + case CALG_3DES: + case CALG_PCT1_MASTER: + case CALG_SSL2_MASTER: + case CALG_SSL3_MASTER: + case CALG_TLS1_MASTER: + *phKey = new_key(hProv, Algid, dwFlags, &pCryptKey); + if (pCryptKey) { + gen_rand_impl(pCryptKey->abKeyValue, RSAENH_MAX_KEY_SIZE); + switch (Algid) { + case CALG_SSL3_MASTER: + pCryptKey->abKeyValue[0] = RSAENH_SSL3_VERSION_MAJOR; + pCryptKey->abKeyValue[1] = RSAENH_SSL3_VERSION_MINOR; + break; + + case CALG_TLS1_MASTER: + pCryptKey->abKeyValue[0] = RSAENH_TLS1_VERSION_MAJOR; + pCryptKey->abKeyValue[1] = RSAENH_TLS1_VERSION_MINOR; + break; + } + setup_key(pCryptKey); + } + break; + + default: + /* MSDN: Algorithm not supported specified by Algid */ + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + + return *phKey != (HCRYPTKEY)INVALID_HANDLE_VALUE; +} + +/****************************************************************************** + * CPGenRandom (RSAENH.@) + * + * Generate a random byte stream. + * + * PARAMS + * hProv [I] Key container that is used to generate random bytes. + * dwLen [I] Specifies the number of requested random data bytes. + * pbBuffer [O] Random bytes will be stored here. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI RSAENH_CPGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer) +{ + TRACE("(hProv=%08lx, dwLen=%d, pbBuffer=%p)\n", hProv, dwLen, pbBuffer); + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + /* MSDN: hProv not containing valid context handle */ + SetLastError(NTE_BAD_UID); + return FALSE; + } + + return gen_rand_impl(pbBuffer, dwLen); +} + +/****************************************************************************** + * CPGetHashParam (RSAENH.@) + * + * Query parameters of an hash object. + * + * PARAMS + * hProv [I] The kea container, which the hash belongs to. + * hHash [I] The hash object that is to be queried. + * dwParam [I] Specifies the parameter that is to be queried. + * pbData [I] Pointer to the buffer where the parameter value will be stored. + * pdwDataLen [I/O] I: Buffer length at pbData, O: Length of the parameter value. + * dwFlags [I] None currently defined. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * Valid dwParams are: HP_ALGID, HP_HASHSIZE, HP_HASHVALUE. The hash will be + * finalized if HP_HASHVALUE is queried. + */ +BOOL WINAPI RSAENH_CPGetHashParam(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, + DWORD *pdwDataLen, DWORD dwFlags) +{ + CRYPTHASH *pCryptHash; + + TRACE("(hProv=%08lx, hHash=%08lx, dwParam=%08x, pbData=%p, pdwDataLen=%p, dwFlags=%08x)\n", + hProv, hHash, dwParam, pbData, pdwDataLen, dwFlags); + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (dwFlags) + { + SetLastError(NTE_BAD_FLAGS); + return FALSE; + } + + if (!lookup_handle(&handle_table, hHash, RSAENH_MAGIC_HASH, + (OBJECTHDR**)&pCryptHash)) + { + SetLastError(NTE_BAD_HASH); + return FALSE; + } + + if (!pdwDataLen) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + switch (dwParam) + { + case HP_ALGID: + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptHash->aiAlgid, + sizeof(ALG_ID)); + + case HP_HASHSIZE: + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptHash->dwHashSize, + sizeof(DWORD)); + + case HP_HASHVAL: + if (pCryptHash->aiAlgid == CALG_TLS1PRF) { + return tls1_prf(hProv, pCryptHash->hKey, &pCryptHash->tpPRFParams.blobLabel, + &pCryptHash->tpPRFParams.blobSeed, pbData, *pdwDataLen); + } + + if ( pbData == NULL ) { + *pdwDataLen = pCryptHash->dwHashSize; + return TRUE; + } + + if (pbData && (pCryptHash->dwState != RSAENH_HASHSTATE_FINISHED)) + { + finalize_hash(pCryptHash); + pCryptHash->dwState = RSAENH_HASHSTATE_FINISHED; + } + + return copy_param(pbData, pdwDataLen, (CONST BYTE*)pCryptHash->abHashValue, + pCryptHash->dwHashSize); + + default: + SetLastError(NTE_BAD_TYPE); + return FALSE; + } +} + +/****************************************************************************** + * CPSetKeyParam (RSAENH.@) + * + * Set a parameter of a key object + * + * PARAMS + * hProv [I] The key container to which the key belongs. + * hKey [I] The key for which a parameter is to be set. + * dwParam [I] Parameter type. See Notes. + * pbData [I] Pointer to the parameter value. + * dwFlags [I] Currently none defined. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + * + * NOTES: + * Defined dwParam types are: + * - KP_MODE: Values MODE_CBC, MODE_ECB, MODE_CFB. + * - KP_MODE_BITS: Shift width for cipher feedback mode. (Currently ignored by MS CSP's) + * - KP_PERMISSIONS: Or'ed combination of CRYPT_ENCRYPT, CRYPT_DECRYPT, + * CRYPT_EXPORT, CRYPT_READ, CRYPT_WRITE, CRYPT_MAC + * - KP_IV: Initialization vector + */ +BOOL WINAPI RSAENH_CPSetKeyParam(HCRYPTPROV hProv, HCRYPTKEY hKey, DWORD dwParam, BYTE *pbData, + DWORD dwFlags) +{ + CRYPTKEY *pCryptKey; + + TRACE("(hProv=%08lx, hKey=%08lx, dwParam=%08x, pbData=%p, dwFlags=%08x)\n", hProv, hKey, + dwParam, pbData, dwFlags); + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (dwFlags) { + SetLastError(NTE_BAD_FLAGS); + return FALSE; + } + + if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey)) + { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + switch (dwParam) { + case KP_MODE: + pCryptKey->dwMode = *(DWORD*)pbData; + return TRUE; + + case KP_MODE_BITS: + pCryptKey->dwModeBits = *(DWORD*)pbData; + return TRUE; + + case KP_PERMISSIONS: + pCryptKey->dwPermissions = *(DWORD*)pbData; + return TRUE; + + case KP_IV: + memcpy(pCryptKey->abInitVector, pbData, pCryptKey->dwBlockLen); + setup_key(pCryptKey); + return TRUE; + + case KP_EFFECTIVE_KEYLEN: + switch (pCryptKey->aiAlgid) { + case CALG_RC2: + if (!pbData) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + else if (!*(DWORD *)pbData || *(DWORD *)pbData > 1024) + { + SetLastError(NTE_BAD_DATA); + return FALSE; + } + else + { + pCryptKey->dwEffectiveKeyLen = *(DWORD *)pbData; + setup_key(pCryptKey); + } + break; + default: + SetLastError(NTE_BAD_TYPE); + return FALSE; + } + return TRUE; + + case KP_SCHANNEL_ALG: + switch (((PSCHANNEL_ALG)pbData)->dwUse) { + case SCHANNEL_ENC_KEY: + memcpy(&pCryptKey->siSChannelInfo.saEncAlg, pbData, sizeof(SCHANNEL_ALG)); + break; + + case SCHANNEL_MAC_KEY: + memcpy(&pCryptKey->siSChannelInfo.saMACAlg, pbData, sizeof(SCHANNEL_ALG)); + break; + + default: + SetLastError(NTE_FAIL); /* FIXME: error code */ + return FALSE; + } + return TRUE; + + case KP_CLIENT_RANDOM: + return copy_data_blob(&pCryptKey->siSChannelInfo.blobClientRandom, (PCRYPT_DATA_BLOB)pbData); + + case KP_SERVER_RANDOM: + return copy_data_blob(&pCryptKey->siSChannelInfo.blobServerRandom, (PCRYPT_DATA_BLOB)pbData); + + default: + SetLastError(NTE_BAD_TYPE); + return FALSE; + } +} + +/****************************************************************************** + * CPGetKeyParam (RSAENH.@) + * + * Query a key parameter. + * + * PARAMS + * hProv [I] The key container, which the key belongs to. + * hHash [I] The key object that is to be queried. + * dwParam [I] Specifies the parameter that is to be queried. + * pbData [I] Pointer to the buffer where the parameter value will be stored. + * pdwDataLen [I/O] I: Buffer length at pbData, O: Length of the parameter value. + * dwFlags [I] None currently defined. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * Defined dwParam types are: + * - KP_MODE: Values MODE_CBC, MODE_ECB, MODE_CFB. + * - KP_MODE_BITS: Shift width for cipher feedback mode. + * (Currently ignored by MS CSP's - always eight) + * - KP_PERMISSIONS: Or'ed combination of CRYPT_ENCRYPT, CRYPT_DECRYPT, + * CRYPT_EXPORT, CRYPT_READ, CRYPT_WRITE, CRYPT_MAC + * - KP_IV: Initialization vector. + * - KP_KEYLEN: Bitwidth of the key. + * - KP_BLOCKLEN: Size of a block cipher block. + * - KP_SALT: Salt value. + */ +BOOL WINAPI RSAENH_CPGetKeyParam(HCRYPTPROV hProv, HCRYPTKEY hKey, DWORD dwParam, BYTE *pbData, + DWORD *pdwDataLen, DWORD dwFlags) +{ + CRYPTKEY *pCryptKey; + DWORD dwBitLen; + + TRACE("(hProv=%08lx, hKey=%08lx, dwParam=%08x, pbData=%p, pdwDataLen=%p dwFlags=%08x)\n", + hProv, hKey, dwParam, pbData, pdwDataLen, dwFlags); + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (dwFlags) { + SetLastError(NTE_BAD_FLAGS); + return FALSE; + } + + if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey)) + { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + switch (dwParam) + { + case KP_IV: + return copy_param(pbData, pdwDataLen, (CONST BYTE*)pCryptKey->abInitVector, + pCryptKey->dwBlockLen); + + case KP_SALT: + return copy_param(pbData, pdwDataLen, + (CONST BYTE*)&pCryptKey->abKeyValue[pCryptKey->dwKeyLen], pCryptKey->dwSaltLen); + + case KP_KEYLEN: + dwBitLen = pCryptKey->dwKeyLen << 3; + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwBitLen, sizeof(DWORD)); + + case KP_EFFECTIVE_KEYLEN: + if (pCryptKey->dwEffectiveKeyLen) + dwBitLen = pCryptKey->dwEffectiveKeyLen; + else + dwBitLen = pCryptKey->dwKeyLen << 3; + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwBitLen, sizeof(DWORD)); + + case KP_BLOCKLEN: + dwBitLen = pCryptKey->dwBlockLen << 3; + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwBitLen, sizeof(DWORD)); + + case KP_MODE: + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptKey->dwMode, sizeof(DWORD)); + + case KP_MODE_BITS: + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptKey->dwModeBits, + sizeof(DWORD)); + + case KP_PERMISSIONS: + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptKey->dwPermissions, + sizeof(DWORD)); + + case KP_ALGID: + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptKey->aiAlgid, sizeof(DWORD)); + + default: + SetLastError(NTE_BAD_TYPE); + return FALSE; + } +} + +/****************************************************************************** + * CPGetProvParam (RSAENH.@) + * + * Query a CSP parameter. + * + * PARAMS + * hProv [I] The key container that is to be queried. + * dwParam [I] Specifies the parameter that is to be queried. + * pbData [I] Pointer to the buffer where the parameter value will be stored. + * pdwDataLen [I/O] I: Buffer length at pbData, O: Length of the parameter value. + * dwFlags [I] CRYPT_FIRST: Start enumeration (for PP_ENUMALGS{_EX}). + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * NOTES: + * Defined dwParam types: + * - PP_CONTAINER: Name of the key container. + * - PP_NAME: Name of the cryptographic service provider. + * - PP_SIG_KEYSIZE_INC: RSA signature keywidth granularity in bits. + * - PP_KEYX_KEYSIZE_INC: RSA key-exchange keywidth granularity in bits. + * - PP_ENUMALGS{_EX}: Query provider capabilities. + */ +BOOL WINAPI RSAENH_CPGetProvParam(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData, + DWORD *pdwDataLen, DWORD dwFlags) +{ + KEYCONTAINER *pKeyContainer; + PROV_ENUMALGS provEnumalgs; + DWORD dwTemp; + HKEY hKey; + + /* This is for dwParam 41, which does not seem to be documented + * on MSDN. IE6 SP1 asks for it in the 'About' dialog, however. + * Returning this BLOB seems to satisfy IE. The marked 0x00 seem + * to be 'don't care's. If you know anything more specific about + * provider parameter 41, please report to wine-devel@winehq.org */ + static CONST BYTE abWTF[96] = { + 0xb0, 0x25, 0x63, 0x86, 0x9c, 0xab, 0xb6, 0x37, + 0xe8, 0x82, /**/0x00,/**/ 0x72, 0x06, 0xb2, /**/0x00,/**/ 0x3b, + 0x60, 0x35, /**/0x00,/**/ 0x3b, 0x88, 0xce, /**/0x00,/**/ 0x82, + 0xbc, 0x7a, /**/0x00,/**/ 0xb7, 0x4f, 0x7e, /**/0x00,/**/ 0xde, + 0x92, 0xf1, /**/0x00,/**/ 0x83, 0xea, 0x5e, /**/0x00,/**/ 0xc8, + 0x12, 0x1e, 0xd4, 0x06, 0xf7, 0x66, /**/0x00,/**/ 0x01, + 0x29, 0xa4, /**/0x00,/**/ 0xf8, 0x24, 0x0c, /**/0x00,/**/ 0x33, + 0x06, 0x80, /**/0x00,/**/ 0x02, 0x46, 0x0b, /**/0x00,/**/ 0x6d, + 0x5b, 0xca, /**/0x00,/**/ 0x9a, 0x10, 0xf0, /**/0x00,/**/ 0x05, + 0x19, 0xd0, /**/0x00,/**/ 0x2c, 0xf6, 0x27, /**/0x00,/**/ 0xaa, + 0x7c, 0x6f, /**/0x00,/**/ 0xb9, 0xd8, 0x72, /**/0x00,/**/ 0x03, + 0xf3, 0x81, /**/0x00,/**/ 0xfa, 0xe8, 0x26, /**/0x00,/**/ 0xca + }; + + TRACE("(hProv=%08lx, dwParam=%08x, pbData=%p, pdwDataLen=%p, dwFlags=%08x)\n", + hProv, dwParam, pbData, pdwDataLen, dwFlags); + + if (!pdwDataLen) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER, + (OBJECTHDR**)&pKeyContainer)) + { + /* MSDN: hProv not containing valid context handle */ + SetLastError(NTE_BAD_UID); + return FALSE; + } + + switch (dwParam) + { + case PP_CONTAINER: + case PP_UNIQUE_CONTAINER:/* MSDN says we can return the same value as PP_CONTAINER */ + return copy_param(pbData, pdwDataLen, (CONST BYTE*)pKeyContainer->szName, + strlen(pKeyContainer->szName)+1); + + case PP_NAME: + return copy_param(pbData, pdwDataLen, (CONST BYTE*)pKeyContainer->szProvName, + strlen(pKeyContainer->szProvName)+1); + + case PP_PROVTYPE: + dwTemp = PROV_RSA_FULL; + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwTemp, sizeof(dwTemp)); + + case PP_KEYSPEC: + dwTemp = AT_SIGNATURE | AT_KEYEXCHANGE; + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwTemp, sizeof(dwTemp)); + + case PP_KEYSET_TYPE: + dwTemp = pKeyContainer->dwFlags & CRYPT_MACHINE_KEYSET; + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwTemp, sizeof(dwTemp)); + + case PP_KEYSTORAGE: + dwTemp = CRYPT_SEC_DESCR; + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwTemp, sizeof(dwTemp)); + + case PP_SIG_KEYSIZE_INC: + case PP_KEYX_KEYSIZE_INC: + dwTemp = 8; + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwTemp, sizeof(dwTemp)); + + case PP_IMPTYPE: + dwTemp = CRYPT_IMPL_SOFTWARE; + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwTemp, sizeof(dwTemp)); + + case PP_VERSION: + dwTemp = 0x00000200; + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwTemp, sizeof(dwTemp)); + + case PP_ENUMCONTAINERS: + if ((dwFlags & CRYPT_FIRST) == CRYPT_FIRST) pKeyContainer->dwEnumContainersCtr = 0; + + if (!pbData) { + *pdwDataLen = (DWORD)MAX_PATH + 1; + return TRUE; + } + + if (!open_container_key("", dwFlags, &hKey)) + { + SetLastError(ERROR_NO_MORE_ITEMS); + return FALSE; + } + + dwTemp = *pdwDataLen; + switch (RegEnumKeyExA(hKey, pKeyContainer->dwEnumContainersCtr, (LPSTR)pbData, &dwTemp, + NULL, NULL, NULL, NULL)) + { + case ERROR_MORE_DATA: + *pdwDataLen = (DWORD)MAX_PATH + 1; + + case ERROR_SUCCESS: + pKeyContainer->dwEnumContainersCtr++; + RegCloseKey(hKey); + return TRUE; + + case ERROR_NO_MORE_ITEMS: + default: + SetLastError(ERROR_NO_MORE_ITEMS); + RegCloseKey(hKey); + return FALSE; + } + + case PP_ENUMALGS: + case PP_ENUMALGS_EX: + if (((pKeyContainer->dwEnumAlgsCtr >= RSAENH_MAX_ENUMALGS-1) || + (!aProvEnumAlgsEx[pKeyContainer->dwPersonality] + [pKeyContainer->dwEnumAlgsCtr+1].aiAlgid)) && + ((dwFlags & CRYPT_FIRST) != CRYPT_FIRST)) + { + SetLastError(ERROR_NO_MORE_ITEMS); + return FALSE; + } + + if (dwParam == PP_ENUMALGS) { + if (pbData && (*pdwDataLen >= sizeof(PROV_ENUMALGS))) + pKeyContainer->dwEnumAlgsCtr = ((dwFlags & CRYPT_FIRST) == CRYPT_FIRST) ? + 0 : pKeyContainer->dwEnumAlgsCtr+1; + + provEnumalgs.aiAlgid = aProvEnumAlgsEx + [pKeyContainer->dwPersonality][pKeyContainer->dwEnumAlgsCtr].aiAlgid; + provEnumalgs.dwBitLen = aProvEnumAlgsEx + [pKeyContainer->dwPersonality][pKeyContainer->dwEnumAlgsCtr].dwDefaultLen; + provEnumalgs.dwNameLen = aProvEnumAlgsEx + [pKeyContainer->dwPersonality][pKeyContainer->dwEnumAlgsCtr].dwNameLen; + memcpy(provEnumalgs.szName, aProvEnumAlgsEx + [pKeyContainer->dwPersonality][pKeyContainer->dwEnumAlgsCtr].szName, + 20*sizeof(CHAR)); + + return copy_param(pbData, pdwDataLen, (CONST BYTE*)&provEnumalgs, + sizeof(PROV_ENUMALGS)); + } else { + if (pbData && (*pdwDataLen >= sizeof(PROV_ENUMALGS_EX))) + pKeyContainer->dwEnumAlgsCtr = ((dwFlags & CRYPT_FIRST) == CRYPT_FIRST) ? + 0 : pKeyContainer->dwEnumAlgsCtr+1; + + return copy_param(pbData, pdwDataLen, + (CONST BYTE*)&aProvEnumAlgsEx + [pKeyContainer->dwPersonality][pKeyContainer->dwEnumAlgsCtr], + sizeof(PROV_ENUMALGS_EX)); + } + + case 41: /* Undocumented. Asked for by IE About dialog */ + return copy_param(pbData, pdwDataLen, abWTF, sizeof(abWTF)); + + default: + /* MSDN: Unknown parameter number in dwParam */ + SetLastError(NTE_BAD_TYPE); + return FALSE; + } +} + +/****************************************************************************** + * CPDeriveKey (RSAENH.@) + * + * Derives a key from a hash value. + * + * PARAMS + * hProv [I] Key container for which a key is to be generated. + * Algid [I] Crypto algorithm identifier for the key to be generated. + * hBaseData [I] Hash from whose value the key will be derived. + * dwFlags [I] See Notes. + * phKey [O] The generated key. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * Defined flags: + * - CRYPT_EXPORTABLE: Key can be exported. + * - CRYPT_NO_SALT: No salt is used for 40 bit keys. + * - CRYPT_CREATE_SALT: Use remaining bits as salt value. + */ +BOOL WINAPI RSAENH_CPDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData, + DWORD dwFlags, HCRYPTKEY *phKey) +{ + CRYPTKEY *pCryptKey, *pMasterKey; + CRYPTHASH *pCryptHash; + BYTE abHashValue[RSAENH_MAX_HASH_SIZE*2]; + DWORD dwLen; + + TRACE("(hProv=%08lx, Algid=%d, hBaseData=%08lx, dwFlags=%08x phKey=%p)\n", hProv, Algid, + hBaseData, dwFlags, phKey); + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (!lookup_handle(&handle_table, hBaseData, RSAENH_MAGIC_HASH, + (OBJECTHDR**)&pCryptHash)) + { + SetLastError(NTE_BAD_HASH); + return FALSE; + } + + if (!phKey) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + switch (GET_ALG_CLASS(Algid)) + { + case ALG_CLASS_DATA_ENCRYPT: + *phKey = new_key(hProv, Algid, dwFlags, &pCryptKey); + if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE; + + /* + * We derive the key material from the hash. + * If the hash value is not large enough for the claimed key, we have to construct + * a larger binary value based on the hash. This is documented in MSDN: CryptDeriveKey. + */ + dwLen = RSAENH_MAX_HASH_SIZE; + RSAENH_CPGetHashParam(pCryptHash->hProv, hBaseData, HP_HASHVAL, abHashValue, &dwLen, 0); + + if (dwLen < pCryptKey->dwKeyLen) { + BYTE pad1[RSAENH_HMAC_DEF_PAD_LEN], pad2[RSAENH_HMAC_DEF_PAD_LEN]; + BYTE old_hashval[RSAENH_MAX_HASH_SIZE]; + DWORD i; + + memcpy(old_hashval, pCryptHash->abHashValue, RSAENH_MAX_HASH_SIZE); + + for (i=0; iabHashValue, pCryptHash->dwHashSize); + + init_hash(pCryptHash); + update_hash(pCryptHash, pad2, RSAENH_HMAC_DEF_PAD_LEN); + finalize_hash(pCryptHash); + memcpy(abHashValue+pCryptHash->dwHashSize, pCryptHash->abHashValue, + pCryptHash->dwHashSize); + + memcpy(pCryptHash->abHashValue, old_hashval, RSAENH_MAX_HASH_SIZE); + } + + memcpy(pCryptKey->abKeyValue, abHashValue, + RSAENH_MIN(pCryptKey->dwKeyLen, sizeof(pCryptKey->abKeyValue))); + break; + + case ALG_CLASS_MSG_ENCRYPT: + if (!lookup_handle(&handle_table, pCryptHash->hKey, RSAENH_MAGIC_KEY, + (OBJECTHDR**)&pMasterKey)) + { + SetLastError(NTE_FAIL); /* FIXME error code */ + return FALSE; + } + + switch (Algid) + { + /* See RFC 2246, chapter 6.3 Key calculation */ + case CALG_SCHANNEL_ENC_KEY: + *phKey = new_key(hProv, pMasterKey->siSChannelInfo.saEncAlg.Algid, + MAKELONG(LOWORD(dwFlags),pMasterKey->siSChannelInfo.saEncAlg.cBits), + &pCryptKey); + if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE; + memcpy(pCryptKey->abKeyValue, + pCryptHash->abHashValue + ( + 2 * (pMasterKey->siSChannelInfo.saMACAlg.cBits / 8) + + ((dwFlags & CRYPT_SERVER) ? + (pMasterKey->siSChannelInfo.saEncAlg.cBits / 8) : 0)), + pMasterKey->siSChannelInfo.saEncAlg.cBits / 8); + memcpy(pCryptKey->abInitVector, + pCryptHash->abHashValue + ( + 2 * (pMasterKey->siSChannelInfo.saMACAlg.cBits / 8) + + 2 * (pMasterKey->siSChannelInfo.saEncAlg.cBits / 8) + + ((dwFlags & CRYPT_SERVER) ? pCryptKey->dwBlockLen : 0)), + pCryptKey->dwBlockLen); + break; + + case CALG_SCHANNEL_MAC_KEY: + *phKey = new_key(hProv, Algid, + MAKELONG(LOWORD(dwFlags),pMasterKey->siSChannelInfo.saMACAlg.cBits), + &pCryptKey); + if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) return FALSE; + memcpy(pCryptKey->abKeyValue, + pCryptHash->abHashValue + ((dwFlags & CRYPT_SERVER) ? + pMasterKey->siSChannelInfo.saMACAlg.cBits / 8 : 0), + pMasterKey->siSChannelInfo.saMACAlg.cBits / 8); + break; + + default: + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + break; + + default: + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + + setup_key(pCryptKey); + return TRUE; +} + +/****************************************************************************** + * CPGetUserKey (RSAENH.@) + * + * Returns a handle to the user's private key-exchange- or signature-key. + * + * PARAMS + * hProv [I] The key container from which a user key is requested. + * dwKeySpec [I] AT_KEYEXCHANGE or AT_SIGNATURE + * phUserKey [O] Handle to the requested key or INVALID_HANDLE_VALUE in case of failure. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + * + * NOTE + * A newly created key container does not contain private user key. Create them with CPGenKey. + */ +BOOL WINAPI RSAENH_CPGetUserKey(HCRYPTPROV hProv, DWORD dwKeySpec, HCRYPTKEY *phUserKey) +{ + KEYCONTAINER *pKeyContainer; + + TRACE("(hProv=%08lx, dwKeySpec=%08x, phUserKey=%p)\n", hProv, dwKeySpec, phUserKey); + + if (!lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER, + (OBJECTHDR**)&pKeyContainer)) + { + /* MSDN: hProv not containing valid context handle */ + SetLastError(NTE_BAD_UID); + return FALSE; + } + + switch (dwKeySpec) + { + case AT_KEYEXCHANGE: + copy_handle(&handle_table, pKeyContainer->hKeyExchangeKeyPair, RSAENH_MAGIC_KEY, + phUserKey); + break; + + case AT_SIGNATURE: + copy_handle(&handle_table, pKeyContainer->hSignatureKeyPair, RSAENH_MAGIC_KEY, + phUserKey); + break; + + default: + *phUserKey = (HCRYPTKEY)INVALID_HANDLE_VALUE; + } + + if (*phUserKey == (HCRYPTKEY)INVALID_HANDLE_VALUE) + { + /* MSDN: dwKeySpec parameter specifies nonexistent key */ + SetLastError(NTE_NO_KEY); + return FALSE; + } + + return TRUE; +} + +/****************************************************************************** + * CPHashData (RSAENH.@) + * + * Updates a hash object with the given data. + * + * PARAMS + * hProv [I] Key container to which the hash object belongs. + * hHash [I] Hash object which is to be updated. + * pbData [I] Pointer to data with which the hash object is to be updated. + * dwDataLen [I] Length of the data. + * dwFlags [I] Currently none defined. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + * + * NOTES + * The actual hash value is queried with CPGetHashParam, which will finalize + * the hash. Updating a finalized hash will fail with a last error NTE_BAD_HASH_STATE. + */ +BOOL WINAPI RSAENH_CPHashData(HCRYPTPROV hProv, HCRYPTHASH hHash, CONST BYTE *pbData, + DWORD dwDataLen, DWORD dwFlags) +{ + CRYPTHASH *pCryptHash; + + TRACE("(hProv=%08lx, hHash=%08lx, pbData=%p, dwDataLen=%d, dwFlags=%08x)\n", + hProv, hHash, pbData, dwDataLen, dwFlags); + + if (dwFlags) + { + SetLastError(NTE_BAD_FLAGS); + return FALSE; + } + + if (!lookup_handle(&handle_table, hHash, RSAENH_MAGIC_HASH, + (OBJECTHDR**)&pCryptHash)) + { + SetLastError(NTE_BAD_HASH); + return FALSE; + } + + if (!get_algid_info(hProv, pCryptHash->aiAlgid) || pCryptHash->aiAlgid == CALG_SSL3_SHAMD5) + { + SetLastError(NTE_BAD_ALGID); + return FALSE; + } + + if (pCryptHash->dwState != RSAENH_HASHSTATE_HASHING) + { + SetLastError(NTE_BAD_HASH_STATE); + return FALSE; + } + + update_hash(pCryptHash, pbData, dwDataLen); + return TRUE; +} + +/****************************************************************************** + * CPHashSessionKey (RSAENH.@) + * + * Updates a hash object with the binary representation of a symmetric key. + * + * PARAMS + * hProv [I] Key container to which the hash object belongs. + * hHash [I] Hash object which is to be updated. + * hKey [I] The symmetric key, whose binary value will be added to the hash. + * dwFlags [I] CRYPT_LITTLE_ENDIAN, if the binary key value shall be interpreted as little endian. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + */ +BOOL WINAPI RSAENH_CPHashSessionKey(HCRYPTPROV hProv, HCRYPTHASH hHash, HCRYPTKEY hKey, + DWORD dwFlags) +{ + BYTE abKeyValue[RSAENH_MAX_KEY_SIZE], bTemp; + CRYPTKEY *pKey; + DWORD i; + + TRACE("(hProv=%08lx, hHash=%08lx, hKey=%08lx, dwFlags=%08x)\n", hProv, hHash, hKey, dwFlags); + + if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pKey) || + (GET_ALG_CLASS(pKey->aiAlgid) != ALG_CLASS_DATA_ENCRYPT)) + { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + if (dwFlags & ~CRYPT_LITTLE_ENDIAN) { + SetLastError(NTE_BAD_FLAGS); + return FALSE; + } + + memcpy(abKeyValue, pKey->abKeyValue, pKey->dwKeyLen); + if (!(dwFlags & CRYPT_LITTLE_ENDIAN)) { + for (i=0; idwKeyLen/2; i++) { + bTemp = abKeyValue[i]; + abKeyValue[i] = abKeyValue[pKey->dwKeyLen-i-1]; + abKeyValue[pKey->dwKeyLen-i-1] = bTemp; + } + } + + return RSAENH_CPHashData(hProv, hHash, abKeyValue, pKey->dwKeyLen, 0); +} + +/****************************************************************************** + * CPReleaseContext (RSAENH.@) + * + * Release a key container. + * + * PARAMS + * hProv [I] Key container to be released. + * dwFlags [I] Currently none defined. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI RSAENH_CPReleaseContext(HCRYPTPROV hProv, DWORD dwFlags) +{ + TRACE("(hProv=%08lx, dwFlags=%08x)\n", hProv, dwFlags); + + if (!release_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + /* MSDN: hProv not containing valid context handle */ + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (dwFlags) { + SetLastError(NTE_BAD_FLAGS); + return FALSE; + } + + return TRUE; +} + +/****************************************************************************** + * CPSetHashParam (RSAENH.@) + * + * Set a parameter of a hash object + * + * PARAMS + * hProv [I] The key container to which the key belongs. + * hHash [I] The hash object for which a parameter is to be set. + * dwParam [I] Parameter type. See Notes. + * pbData [I] Pointer to the parameter value. + * dwFlags [I] Currently none defined. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + * + * NOTES + * Currently only the HP_HMAC_INFO dwParam type is defined. + * The HMAC_INFO struct will be deep copied into the hash object. + * See Internet RFC 2104 for details on the HMAC algorithm. + */ +BOOL WINAPI RSAENH_CPSetHashParam(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwParam, + BYTE *pbData, DWORD dwFlags) +{ + CRYPTHASH *pCryptHash; + CRYPTKEY *pCryptKey; + int i; + + TRACE("(hProv=%08lx, hHash=%08lx, dwParam=%08x, pbData=%p, dwFlags=%08x)\n", + hProv, hHash, dwParam, pbData, dwFlags); + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (dwFlags) { + SetLastError(NTE_BAD_FLAGS); + return FALSE; + } + + if (!lookup_handle(&handle_table, hHash, RSAENH_MAGIC_HASH, + (OBJECTHDR**)&pCryptHash)) + { + SetLastError(NTE_BAD_HASH); + return FALSE; + } + + switch (dwParam) { + case HP_HMAC_INFO: + free_hmac_info(pCryptHash->pHMACInfo); + if (!copy_hmac_info(&pCryptHash->pHMACInfo, (PHMAC_INFO)pbData)) return FALSE; + + if (!lookup_handle(&handle_table, pCryptHash->hKey, RSAENH_MAGIC_KEY, + (OBJECTHDR**)&pCryptKey)) + { + SetLastError(NTE_FAIL); /* FIXME: correct error code? */ + return FALSE; + } + + for (i=0; idwKeyLen,pCryptHash->pHMACInfo->cbInnerString); i++) { + pCryptHash->pHMACInfo->pbInnerString[i] ^= pCryptKey->abKeyValue[i]; + } + for (i=0; idwKeyLen,pCryptHash->pHMACInfo->cbOuterString); i++) { + pCryptHash->pHMACInfo->pbOuterString[i] ^= pCryptKey->abKeyValue[i]; + } + + init_hash(pCryptHash); + return TRUE; + + case HP_HASHVAL: + memcpy(pCryptHash->abHashValue, pbData, pCryptHash->dwHashSize); + pCryptHash->dwState = RSAENH_HASHSTATE_FINISHED; + return TRUE; + + case HP_TLS1PRF_SEED: + return copy_data_blob(&pCryptHash->tpPRFParams.blobSeed, (PCRYPT_DATA_BLOB)pbData); + + case HP_TLS1PRF_LABEL: + return copy_data_blob(&pCryptHash->tpPRFParams.blobLabel, (PCRYPT_DATA_BLOB)pbData); + + default: + SetLastError(NTE_BAD_TYPE); + return FALSE; + } +} + +/****************************************************************************** + * CPSetProvParam (RSAENH.@) + */ +BOOL WINAPI RSAENH_CPSetProvParam(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData, DWORD dwFlags) +{ + FIXME("(stub)\n"); + return FALSE; +} + +/****************************************************************************** + * CPSignHash (RSAENH.@) + * + * Sign a hash object + * + * PARAMS + * hProv [I] The key container, to which the hash object belongs. + * hHash [I] The hash object to be signed. + * dwKeySpec [I] AT_SIGNATURE or AT_KEYEXCHANGE: Key used to generate the signature. + * sDescription [I] Should be NULL for security reasons. + * dwFlags [I] 0, CRYPT_NOHASHOID or CRYPT_X931_FORMAT: Format of the signature. + * pbSignature [O] Buffer, to which the signature will be stored. May be NULL to query SigLen. + * pdwSigLen [I/O] Size of the buffer (in), Length of the signature (out) + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI RSAENH_CPSignHash(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwKeySpec, + LPCWSTR sDescription, DWORD dwFlags, BYTE *pbSignature, + DWORD *pdwSigLen) +{ + HCRYPTKEY hCryptKey; + CRYPTKEY *pCryptKey; + DWORD dwHashLen; + BYTE abHashValue[RSAENH_MAX_HASH_SIZE]; + ALG_ID aiAlgid; + + TRACE("(hProv=%08lx, hHash=%08lx, dwKeySpec=%08x, sDescription=%s, dwFlags=%08x, " + "pbSignature=%p, pdwSigLen=%p)\n", hProv, hHash, dwKeySpec, debugstr_w(sDescription), + dwFlags, pbSignature, pdwSigLen); + + if (dwFlags & ~(CRYPT_NOHASHOID|CRYPT_X931_FORMAT)) { + SetLastError(NTE_BAD_FLAGS); + return FALSE; + } + + if (!RSAENH_CPGetUserKey(hProv, dwKeySpec, &hCryptKey)) return FALSE; + + if (!lookup_handle(&handle_table, hCryptKey, RSAENH_MAGIC_KEY, + (OBJECTHDR**)&pCryptKey)) + { + SetLastError(NTE_NO_KEY); + return FALSE; + } + + if (!pbSignature) { + *pdwSigLen = pCryptKey->dwKeyLen; + return TRUE; + } + if (pCryptKey->dwKeyLen > *pdwSigLen) + { + SetLastError(ERROR_MORE_DATA); + *pdwSigLen = pCryptKey->dwKeyLen; + return FALSE; + } + *pdwSigLen = pCryptKey->dwKeyLen; + + if (sDescription) { + if (!RSAENH_CPHashData(hProv, hHash, (CONST BYTE*)sDescription, + (DWORD)lstrlenW(sDescription)*sizeof(WCHAR), 0)) + { + return FALSE; + } + } + + dwHashLen = sizeof(DWORD); + if (!RSAENH_CPGetHashParam(hProv, hHash, HP_ALGID, (BYTE*)&aiAlgid, &dwHashLen, 0)) return FALSE; + + dwHashLen = RSAENH_MAX_HASH_SIZE; + if (!RSAENH_CPGetHashParam(hProv, hHash, HP_HASHVAL, abHashValue, &dwHashLen, 0)) return FALSE; + + + if (!build_hash_signature(pbSignature, *pdwSigLen, aiAlgid, abHashValue, dwHashLen, dwFlags)) { + return FALSE; + } + + return encrypt_block_impl(pCryptKey->aiAlgid, PK_PRIVATE, &pCryptKey->context, pbSignature, pbSignature, RSAENH_ENCRYPT); +} + +/****************************************************************************** + * CPVerifySignature (RSAENH.@) + * + * Verify the signature of a hash object. + * + * PARAMS + * hProv [I] The key container, to which the hash belongs. + * hHash [I] The hash for which the signature is verified. + * pbSignature [I] The binary signature. + * dwSigLen [I] Length of the signature BLOB. + * hPubKey [I] Public key used to verify the signature. + * sDescription [I] Should be NULL for security reasons. + * dwFlags [I] 0, CRYPT_NOHASHOID or CRYPT_X931_FORMAT: Format of the signature. + * + * RETURNS + * Success: TRUE (Signature is valid) + * Failure: FALSE (GetLastError() == NTE_BAD_SIGNATURE, if signature is invalid) + */ +BOOL WINAPI RSAENH_CPVerifySignature(HCRYPTPROV hProv, HCRYPTHASH hHash, CONST BYTE *pbSignature, + DWORD dwSigLen, HCRYPTKEY hPubKey, LPCWSTR sDescription, + DWORD dwFlags) +{ + BYTE *pbConstructed = NULL, *pbDecrypted = NULL; + CRYPTKEY *pCryptKey; + DWORD dwHashLen; + ALG_ID aiAlgid; + BYTE abHashValue[RSAENH_MAX_HASH_SIZE]; + BOOL res = FALSE; + + TRACE("(hProv=%08lx, hHash=%08lx, pbSignature=%p, dwSigLen=%d, hPubKey=%08lx, sDescription=%s, " + "dwFlags=%08x)\n", hProv, hHash, pbSignature, dwSigLen, hPubKey, debugstr_w(sDescription), + dwFlags); + + if (dwFlags & ~(CRYPT_NOHASHOID|CRYPT_X931_FORMAT)) { + SetLastError(NTE_BAD_FLAGS); + return FALSE; + } + + if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER)) + { + SetLastError(NTE_BAD_UID); + return FALSE; + } + + if (!lookup_handle(&handle_table, hPubKey, RSAENH_MAGIC_KEY, + (OBJECTHDR**)&pCryptKey)) + { + SetLastError(NTE_BAD_KEY); + return FALSE; + } + + /* in Microsoft implementation, the signature length is checked before + * the signature pointer. + */ + if (dwSigLen != pCryptKey->dwKeyLen) + { + SetLastError(NTE_BAD_SIGNATURE); + return FALSE; + } + + if (!hHash || !pbSignature) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (sDescription) { + if (!RSAENH_CPHashData(hProv, hHash, (CONST BYTE*)sDescription, + (DWORD)lstrlenW(sDescription)*sizeof(WCHAR), 0)) + { + return FALSE; + } + } + + dwHashLen = sizeof(DWORD); + if (!RSAENH_CPGetHashParam(hProv, hHash, HP_ALGID, (BYTE*)&aiAlgid, &dwHashLen, 0)) return FALSE; + + dwHashLen = RSAENH_MAX_HASH_SIZE; + if (!RSAENH_CPGetHashParam(hProv, hHash, HP_HASHVAL, abHashValue, &dwHashLen, 0)) return FALSE; + + pbConstructed = HeapAlloc(GetProcessHeap(), 0, dwSigLen); + if (!pbConstructed) { + SetLastError(NTE_NO_MEMORY); + goto cleanup; + } + + pbDecrypted = HeapAlloc(GetProcessHeap(), 0, dwSigLen); + if (!pbDecrypted) { + SetLastError(NTE_NO_MEMORY); + goto cleanup; + } + + if (!encrypt_block_impl(pCryptKey->aiAlgid, PK_PUBLIC, &pCryptKey->context, pbSignature, pbDecrypted, + RSAENH_DECRYPT)) + { + goto cleanup; + } + + if (!build_hash_signature(pbConstructed, dwSigLen, aiAlgid, abHashValue, dwHashLen, dwFlags)) { + goto cleanup; + } + + if (memcmp(pbDecrypted, pbConstructed, dwSigLen)) { + SetLastError(NTE_BAD_SIGNATURE); + goto cleanup; + } + + res = TRUE; +cleanup: + HeapFree(GetProcessHeap(), 0, pbConstructed); + HeapFree(GetProcessHeap(), 0, pbDecrypted); + return res; +} + +static const WCHAR szProviderKeys[4][97] = { + { 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r', + 'a','p','h','y','\\','D','e','f','a','u','l','t','s','\\','P','r','o','v', + 'i','d','e','r','\\','M','i','c','r','o','s','o','f','t',' ','B','a','s', + 'e',' ','C','r','y','p','t','o','g','r','a','p','h','i','c',' ','P','r', + 'o','v','i','d','e','r',' ','v','1','.','0',0 }, + { 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r', + 'a','p','h','y','\\','D','e','f','a','u','l','t','s','\\','P','r','o','v', + 'i','d','e','r','\\','M','i','c','r','o','s','o','f','t',' ', + 'E','n','h','a','n','c','e','d', + ' ','C','r','y','p','t','o','g','r','a','p','h','i','c',' ','P','r', + 'o','v','i','d','e','r',' ','v','1','.','0',0 }, + { 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r', + 'a','p','h','y','\\','D','e','f','a','u','l','t','s','\\','P','r','o','v', + 'i','d','e','r','\\','M','i','c','r','o','s','o','f','t',' ','S','t','r','o','n','g', + ' ','C','r','y','p','t','o','g','r','a','p','h','i','c',' ','P','r', + 'o','v','i','d','e','r',0 }, + { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', + 'C','r','y','p','t','o','g','r','a','p','h','y','\\','D','e','f','a','u','l','t','s','\\', + 'P','r','o','v','i','d','e','r','\\','M','i','c','r','o','s','o','f','t',' ', + 'R','S','A',' ','S','C','h','a','n','n','e','l',' ', + 'C','r','y','p','t','o','g','r','a','p','h','i','c',' ','P','r','o','v','i','d','e','r',0 } +}; +static const WCHAR szDefaultKeys[2][65] = { + { 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r', + 'a','p','h','y','\\','D','e','f','a','u','l','t','s','\\','P','r','o','v', + 'i','d','e','r',' ','T','y','p','e','s','\\','T','y','p','e',' ','0','0','1',0 }, + { 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r', + 'a','p','h','y','\\','D','e','f','a','u','l','t','s','\\','P','r','o','v', + 'i','d','e','r',' ','T','y','p','e','s','\\','T','y','p','e',' ','0','1','2',0 } +}; + + +/****************************************************************************** + * DllRegisterServer (RSAENH.@) + * + * Dll self registration. + * + * PARAMS + * + * RETURNS + * Success: S_OK. + * Failure: != S_OK + * + * NOTES + * Registers the following keys: + * - HKLM\Software\Microsoft\Cryptography\Defaults\Provider\ + * Microsoft Base Cryptographic Provider v1.0 + * - HKLM\Software\Microsoft\Cryptography\Defaults\Provider\ + * Microsoft Enhanced Cryptographic Provider + * - HKLM\Software\Microsoft\Cryptography\Defaults\Provider\ + * Microsoft Strong Cryptographpic Provider + * - HKLM\Software\Microsoft\Cryptography\Defaults\Provider Types\Type 001 + */ +HRESULT WINAPI DllRegisterServer(void) +{ + HKEY key; + DWORD dp; + long apiRet; + int i; + + for (i=0; i<4; i++) { + apiRet = RegCreateKeyExW(HKEY_LOCAL_MACHINE, szProviderKeys[i], 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &dp); + + if (apiRet == ERROR_SUCCESS) + { + if (dp == REG_CREATED_NEW_KEY) + { + static const WCHAR szImagePath[] = { 'I','m','a','g','e',' ','P','a','t','h',0 }; + static const WCHAR szRSABase[] = { 'r','s','a','e','n','h','.','d','l','l',0 }; + static const WCHAR szType[] = { 'T','y','p','e',0 }; + static const WCHAR szSignature[] = { 'S','i','g','n','a','t','u','r','e',0 }; + DWORD type = (i == 3) ? PROV_RSA_SCHANNEL : PROV_RSA_FULL; + DWORD sign = 0xdeadbeef; + RegSetValueExW(key, szImagePath, 0, REG_SZ, (const BYTE *)szRSABase, + (lstrlenW(szRSABase) + 1) * sizeof(WCHAR)); + RegSetValueExW(key, szType, 0, REG_DWORD, (LPBYTE)&type, sizeof(type)); + RegSetValueExW(key, szSignature, 0, REG_BINARY, (LPBYTE)&sign, sizeof(sign)); + } + RegCloseKey(key); + } + } + + for (i=0; i<2; i++) { + apiRet = RegCreateKeyExW(HKEY_LOCAL_MACHINE, szDefaultKeys[i], 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &dp); + if (apiRet == ERROR_SUCCESS) + { + if (dp == REG_CREATED_NEW_KEY) + { + static const WCHAR szName[] = { 'N','a','m','e',0 }; + static const WCHAR szRSAName[2][46] = { + { 'M','i','c','r','o','s','o','f','t',' ', 'B','a','s','e',' ', + 'C','r','y','p','t','o','g','r','a','p','h','i','c',' ', + 'P','r','o','v','i','d','e','r',' ','v','1','.','0',0 }, + { 'M','i','c','r','o','s','o','f','t',' ','R','S','A',' ', + 'S','C','h','a','n','n','e','l',' ', + 'C','r','y','p','t','o','g','r','a','p','h','i','c',' ', + 'P','r','o','v','i','d','e','r',0 } }; + static const WCHAR szTypeName[] = { 'T','y','p','e','N','a','m','e',0 }; + static const WCHAR szRSATypeName[2][38] = { + { 'R','S','A',' ','F','u','l','l',' ', + '(','S','i','g','n','a','t','u','r','e',' ','a','n','d',' ', + 'K','e','y',' ','E','x','c','h','a','n','g','e',')',0 }, + { 'R','S','A',' ','S','C','h','a','n','n','e','l',0 } }; + + RegSetValueExW(key, szName, 0, REG_SZ, + (const BYTE *)szRSAName[i], lstrlenW(szRSAName[i])*sizeof(WCHAR)+sizeof(WCHAR)); + RegSetValueExW(key, szTypeName, 0, REG_SZ, + (const BYTE *)szRSATypeName[i], lstrlenW(szRSATypeName[i])*sizeof(WCHAR)+sizeof(WCHAR)); + } + } + RegCloseKey(key); + } + + return HRESULT_FROM_WIN32(apiRet); +} + +/****************************************************************************** + * DllUnregisterServer (RSAENH.@) + * + * Dll self unregistration. + * + * PARAMS + * + * RETURNS + * Success: S_OK + * + * NOTES + * For the relevant keys see DllRegisterServer. + */ +HRESULT WINAPI DllUnregisterServer(void) +{ + RegDeleteKeyW(HKEY_LOCAL_MACHINE, szProviderKeys[0]); + RegDeleteKeyW(HKEY_LOCAL_MACHINE, szProviderKeys[1]); + RegDeleteKeyW(HKEY_LOCAL_MACHINE, szProviderKeys[2]); + RegDeleteKeyW(HKEY_LOCAL_MACHINE, szProviderKeys[3]); + RegDeleteKeyW(HKEY_LOCAL_MACHINE, szDefaultKeys[0]); + RegDeleteKeyW(HKEY_LOCAL_MACHINE, szDefaultKeys[1]); + return S_OK; +} diff --git a/reactos/dll/win32/rsaenh/rsaenh.rbuild b/reactos/dll/win32/rsaenh/rsaenh.rbuild new file mode 100644 index 00000000000..a14510c48b7 --- /dev/null +++ b/reactos/dll/win32/rsaenh/rsaenh.rbuild @@ -0,0 +1,25 @@ + + + + + + . + include/reactos/wine + + wine + crypt32 + advapi32 + kernel32 + ntdll + des.c + handle.c + implglue.c + md2.c + mpi.c + rc2.c + rc4.c + rsa.c + rsaenh.c + version.rc + rsaenh.spec + diff --git a/reactos/dll/win32/rsaenh/rsaenh.spec b/reactos/dll/win32/rsaenh/rsaenh.spec new file mode 100644 index 00000000000..e3ceb02bc0d --- /dev/null +++ b/reactos/dll/win32/rsaenh/rsaenh.spec @@ -0,0 +1,27 @@ +@ stdcall CPAcquireContext(ptr str long ptr) RSAENH_CPAcquireContext +@ stdcall CPCreateHash(long long ptr long ptr) RSAENH_CPCreateHash +@ stdcall CPDecrypt(long long long long long ptr ptr) RSAENH_CPDecrypt +@ stdcall CPDeriveKey(long long long long ptr) RSAENH_CPDeriveKey +@ stdcall CPDestroyHash(long long) RSAENH_CPDestroyHash +@ stdcall CPDestroyKey(long long) RSAENH_CPDestroyKey +@ stdcall CPDuplicateHash(long long ptr long ptr) RSAENH_CPDuplicateHash +@ stdcall CPDuplicateKey(long long ptr long ptr) RSAENH_CPDuplicateKey +@ stdcall CPEncrypt(long long long long long ptr ptr long) RSAENH_CPEncrypt +@ stdcall CPExportKey(long long long long long ptr ptr) RSAENH_CPExportKey +@ stdcall CPGenKey(long long long ptr) RSAENH_CPGenKey +@ stdcall CPGenRandom(long long ptr) RSAENH_CPGenRandom +@ stdcall CPGetHashParam(long long long ptr ptr long) RSAENH_CPGetHashParam +@ stdcall CPGetKeyParam(long long long ptr ptr long) RSAENH_CPGetKeyParam +@ stdcall CPGetProvParam(long long ptr ptr long) RSAENH_CPGetProvParam +@ stdcall CPGetUserKey(long long ptr) RSAENH_CPGetUserKey +@ stdcall CPHashData(long long ptr long long) RSAENH_CPHashData +@ stdcall CPHashSessionKey(long long long long) RSAENH_CPHashSessionKey +@ stdcall CPImportKey(long ptr long long long ptr) RSAENH_CPImportKey +@ stdcall CPReleaseContext(long long) RSAENH_CPReleaseContext +@ stdcall CPSetHashParam(long long long ptr long) RSAENH_CPSetHashParam +@ stdcall CPSetKeyParam(long long long ptr long) RSAENH_CPSetKeyParam +@ stdcall CPSetProvParam(long long ptr long) RSAENH_CPSetProvParam +@ stdcall CPSignHash(long long long wstr long ptr ptr) RSAENH_CPSignHash +@ stdcall CPVerifySignature(long long ptr long long wstr long) RSAENH_CPVerifySignature +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() diff --git a/reactos/dll/win32/rsaenh/rsaenh_ros.diff b/reactos/dll/win32/rsaenh/rsaenh_ros.diff new file mode 100644 index 00000000000..4dfb5634659 --- /dev/null +++ b/reactos/dll/win32/rsaenh/rsaenh_ros.diff @@ -0,0 +1,30 @@ +Index: handle.h +=================================================================== +--- handle.h (revision 30501) ++++ handle.h (working copy) +@@ -48,6 +48,10 @@ + unsigned int iNextFree; + } HANDLETABLEENTRY; + ++/* Prevent conflict with wingdi.h */ ++#define tagHANDLETABLE tagHANDLETABLE_RSA ++#define HANDLETABLE HANDLETABLE_RSA ++ + typedef struct tagHANDLETABLE + { + unsigned int iEntries; +Index: rsaenh.c +=================================================================== +--- rsaenh.c (revision 30501) ++++ rsaenh.c (working copy) +@@ -33,9 +33,9 @@ + #include "winbase.h" + #include "winreg.h" + #include "wincrypt.h" ++#include "objbase.h" + #include "handle.h" + #include "implglue.h" +-#include "objbase.h" + + WINE_DEFAULT_DEBUG_CHANNEL(crypt); + diff --git a/reactos/dll/win32/rsaenh/tomcrypt.h b/reactos/dll/win32/rsaenh/tomcrypt.h new file mode 100644 index 00000000000..53c2f40b39a --- /dev/null +++ b/reactos/dll/win32/rsaenh/tomcrypt.h @@ -0,0 +1,611 @@ +/* + * dlls/rsaenh/tomcrypt.h + * Function prototypes, type definitions and constant definitions + * for LibTomCrypt code. + * + * Copyright 2004 Michael Jung + * Based on public domain code by Tom St Denis (tomstdenis@iahu.ca) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * This file contains code from the LibTomCrypt cryptographic + * library written by Tom St Denis (tomstdenis@iahu.ca). LibTomCrypt + * is in the public domain. The code in this file is tailored to + * special requirements. Take a look at http://libtomcrypt.org for the + * original version. + */ + +#ifndef __WINE_TOMCRYPT_H_ +#define __WINE_TOMCRYPT_H_ + +#include +#include +#include +#include +#include "basetsd.h" + +/* error codes [will be expanded in future releases] */ +enum { + CRYPT_OK=0, /* Result OK */ + CRYPT_ERROR, /* Generic Error */ + CRYPT_NOP, /* Not a failure but no operation was performed */ + + CRYPT_INVALID_KEYSIZE, /* Invalid key size given */ + CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */ + CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */ + + CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */ + CRYPT_INVALID_PACKET, /* Invalid input packet given */ + + CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */ + CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */ + + CRYPT_INVALID_CIPHER, /* Invalid cipher specified */ + CRYPT_INVALID_HASH, /* Invalid hash specified */ + CRYPT_INVALID_PRNG, /* Invalid PRNG specified */ + + CRYPT_MEM, /* Out of memory */ + + CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */ + CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */ + + CRYPT_INVALID_ARG, /* Generic invalid argument */ + CRYPT_FILE_NOTFOUND, /* File Not Found */ + + CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */ + CRYPT_PK_INVALID_SYSTEM,/* Invalid PK system specified */ + CRYPT_PK_DUP, /* Duplicate key already in key ring */ + CRYPT_PK_NOT_FOUND, /* Key not found in keyring */ + CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */ + + CRYPT_INVALID_PRIME_SIZE/* Invalid size of prime requested */ +}; + +#define CONST64(a,b) ((((ULONG64)(a)) << 32) | (b)) +typedef ULONG64 ulong64; + +/* this is the "32-bit at least" data type + * Re-define it to suit your platform but it must be at least 32-bits + */ +typedef ULONG32 ulong32; + +/* ---- HELPER MACROS ---- */ +#define STORE32H(x, y) \ + { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ + (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } + +#define LOAD32H(x, y) \ + { x = ((unsigned long)((y)[0] & 255)<<24) | \ + ((unsigned long)((y)[1] & 255)<<16) | \ + ((unsigned long)((y)[2] & 255)<<8) | \ + ((unsigned long)((y)[3] & 255)); } + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) + +static inline unsigned ROR(unsigned word, int i) +{ + __asm__("rorl %%cl,%0" + :"=r" (word) + :"0" (word),"c" (i)); + return word; +} + +#else + +/* rotates the hard way */ +#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | \ + ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) + +#endif + +#undef MIN +#define MIN(x, y) ( ((x)<(y))?(x):(y) ) + +#define byte(x, n) (((x) >> (8 * (n))) & 255) + +typedef struct tag_rc2_key { + unsigned xkey[64]; +} rc2_key; + +typedef struct tag_des_key { + ulong32 ek[32], dk[32]; +} des_key; + +typedef struct tag_des3_key { + ulong32 ek[3][32], dk[3][32]; +} des3_key; + +int rc2_setup(const unsigned char *key, int keylen, int bits, int num_rounds, rc2_key *skey); +void rc2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, rc2_key *key); +void rc2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, rc2_key *key); + +int des_setup(const unsigned char *key, int keylen, int num_rounds, des_key *skey); +void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const des_key *key); +void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const des_key *key); + +int des3_setup(const unsigned char *key, int keylen, int num_rounds, des3_key *skey); +void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, const des3_key *key); +void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, const des3_key *key); + +typedef struct tag_md2_state { + unsigned char chksum[16], X[48], buf[16]; + unsigned long curlen; +} md2_state; + +int md2_init(md2_state * md); +int md2_process(md2_state * md, const unsigned char *buf, unsigned long len); +int md2_done(md2_state * md, unsigned char *hash); + +struct rc4_prng { + int x, y; + unsigned char buf[256]; +}; + +typedef union Prng_state { + struct rc4_prng rc4; +} prng_state; + +int rc4_start(prng_state *prng); +int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng); +int rc4_ready(prng_state *prng); +unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng); + +/* some default configurations. + * + * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits + * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits + * + * At the very least a mp_digit must be able to hold 7 bits + * [any size beyond that is ok provided it doesn't overflow the data type] + */ +typedef unsigned long mp_digit; +typedef ulong64 mp_word; +#define DIGIT_BIT 28 + +#define MP_DIGIT_BIT DIGIT_BIT +#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) +#define MP_DIGIT_MAX MP_MASK + +/* equalities */ +#define MP_LT -1 /* less than */ +#define MP_EQ 0 /* equal to */ +#define MP_GT 1 /* greater than */ + +#define MP_ZPOS 0 /* positive integer */ +#define MP_NEG 1 /* negative */ + +#define MP_OKAY 0 /* ok result */ +#define MP_MEM -2 /* out of mem */ +#define MP_VAL -3 /* invalid input */ +#define MP_RANGE MP_VAL + +#define MP_YES 1 /* yes response */ +#define MP_NO 0 /* no response */ + +/* Primality generation flags */ +#define LTM_PRIME_BBS 0x0001 /* BBS style prime */ +#define LTM_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */ +#define LTM_PRIME_2MSB_OFF 0x0004 /* force 2nd MSB to 0 */ +#define LTM_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */ + +typedef int mp_err; + +/* define this to use lower memory usage routines (exptmods mostly) */ +/* #define MP_LOW_MEM */ + +#define MP_PREC 64 /* default digits of precision */ + +/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ +#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) + +/* the infamous mp_int structure */ +typedef struct { + int used, alloc, sign; + mp_digit *dp; +} mp_int; + +/* callback for mp_prime_random, should fill dst with random bytes and return how many read [up to len] */ +typedef int ltm_prime_callback(unsigned char *dst, int len, void *dat); + +#define DIGIT(m,k) ((m)->dp[(k)]) + +/* error code to char* string */ +char *mp_error_to_string(int code); + +/* ---> init and deinit bignum functions <--- */ +/* init a bignum */ +int mp_init(mp_int *a); + +/* free a bignum */ +void mp_clear(mp_int *a); + +/* init a null terminated series of arguments */ +int mp_init_multi(mp_int *mp, ...); + +/* clear a null terminated series of arguments */ +void mp_clear_multi(mp_int *mp, ...); + +/* exchange two ints */ +void mp_exch(mp_int *a, mp_int *b); + +/* shrink ram required for a bignum */ +int mp_shrink(mp_int *a); + +/* grow an int to a given size */ +int mp_grow(mp_int *a, int size); + +/* init to a given number of digits */ +int mp_init_size(mp_int *a, int size); + +/* ---> Basic Manipulations <--- */ +#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) +#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) +#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) + +/* set to zero */ +void mp_zero(mp_int *a); + +/* set to a digit */ +void mp_set(mp_int *a, mp_digit b); + +/* set a 32-bit const */ +int mp_set_int(mp_int *a, unsigned long b); + +/* get a 32-bit value */ +unsigned long mp_get_int(const mp_int * a); + +/* initialize and set a digit */ +int mp_init_set (mp_int * a, mp_digit b); + +/* initialize and set 32-bit value */ +int mp_init_set_int (mp_int * a, unsigned long b); + +/* copy, b = a */ +int mp_copy(const mp_int *a, mp_int *b); + +/* inits and copies, a = b */ +int mp_init_copy(mp_int *a, const mp_int *b); + +/* trim unused digits */ +void mp_clamp(mp_int *a); + +/* ---> digit manipulation <--- */ + +/* right shift by "b" digits */ +void mp_rshd(mp_int *a, int b); + +/* left shift by "b" digits */ +int mp_lshd(mp_int *a, int b); + +/* c = a / 2**b */ +int mp_div_2d(const mp_int *a, int b, mp_int *c, mp_int *d); + +/* b = a/2 */ +int mp_div_2(const mp_int *a, mp_int *b); + +/* c = a * 2**b */ +int mp_mul_2d(const mp_int *a, int b, mp_int *c); + +/* b = a*2 */ +int mp_mul_2(const mp_int *a, mp_int *b); + +/* c = a mod 2**d */ +int mp_mod_2d(const mp_int *a, int b, mp_int *c); + +/* computes a = 2**b */ +int mp_2expt(mp_int *a, int b); + +/* Counts the number of lsbs which are zero before the first zero bit */ +int mp_cnt_lsb(const mp_int *a); + +/* I Love Earth! */ + +/* makes a pseudo-random int of a given size */ +int mp_rand(mp_int *a, int digits); + +/* ---> binary operations <--- */ +/* c = a XOR b */ +int mp_xor(mp_int *a, mp_int *b, mp_int *c); + +/* c = a OR b */ +int mp_or(mp_int *a, mp_int *b, mp_int *c); + +/* c = a AND b */ +int mp_and(mp_int *a, mp_int *b, mp_int *c); + +/* ---> Basic arithmetic <--- */ + +/* b = -a */ +int mp_neg(mp_int *a, mp_int *b); + +/* b = |a| */ +int mp_abs(const mp_int *a, mp_int *b); + +/* compare a to b */ +int mp_cmp(const mp_int *a, const mp_int *b); + +/* compare |a| to |b| */ +int mp_cmp_mag(const mp_int *a, const mp_int *b); + +/* c = a + b */ +int mp_add(mp_int *a, mp_int *b, mp_int *c); + +/* c = a - b */ +int mp_sub(mp_int *a, mp_int *b, mp_int *c); + +/* c = a * b */ +int mp_mul(const mp_int *a, const mp_int *b, mp_int *c); + +/* b = a*a */ +int mp_sqr(const mp_int *a, mp_int *b); + +/* a/b => cb + d == a */ +int mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d); + +/* c = a mod b, 0 <= c < b */ +int mp_mod(const mp_int *a, mp_int *b, mp_int *c); + +/* ---> single digit functions <--- */ + +/* compare against a single digit */ +int mp_cmp_d(const mp_int *a, mp_digit b); + +/* c = a + b */ +int mp_add_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a - b */ +int mp_sub_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a * b */ +int mp_mul_d(const mp_int *a, mp_digit b, mp_int *c); + +/* a/b => cb + d == a */ +int mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d); + +/* a/3 => 3c + d == a */ +int mp_div_3(mp_int *a, mp_int *c, mp_digit *d); + +/* c = a**b */ +int mp_expt_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a mod b, 0 <= c < b */ +int mp_mod_d(const mp_int *a, mp_digit b, mp_digit *c); + +/* ---> number theory <--- */ + +/* d = a + b (mod c) */ +int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a - b (mod c) */ +int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a * b (mod c) */ +int mp_mulmod(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d); + +/* c = a * a (mod b) */ +int mp_sqrmod(const mp_int *a, mp_int *b, mp_int *c); + +/* c = 1/a (mod b) */ +int mp_invmod(const mp_int *a, mp_int *b, mp_int *c); + +/* c = (a, b) */ +int mp_gcd(const mp_int *a, const mp_int *b, mp_int *c); + +/* produces value such that U1*a + U2*b = U3 */ +int mp_exteuclid(mp_int *a, mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3); + +/* c = [a, b] or (a*b)/(a, b) */ +int mp_lcm(const mp_int *a, const mp_int *b, mp_int *c); + +/* finds one of the b'th root of a, such that |c|**b <= |a| + * + * returns error if a < 0 and b is even + */ +int mp_n_root(mp_int *a, mp_digit b, mp_int *c); + +/* special sqrt algo */ +int mp_sqrt(mp_int *arg, mp_int *ret); + +/* is number a square? */ +int mp_is_square(mp_int *arg, int *ret); + +/* computes the jacobi c = (a | n) (or Legendre if b is prime) */ +int mp_jacobi(mp_int *a, mp_int *n, int *c); + +/* used to setup the Barrett reduction for a given modulus b */ +int mp_reduce_setup(mp_int *a, const mp_int *b); + +/* Barrett Reduction, computes a (mod b) with a precomputed value c + * + * Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely + * compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code]. + */ +int mp_reduce(mp_int *a, const mp_int *b, const mp_int *c); + +/* setups the montgomery reduction */ +int mp_montgomery_setup(const mp_int *a, mp_digit *mp); + +/* computes a = B**n mod b without division or multiplication useful for + * normalizing numbers in a Montgomery system. + */ +int mp_montgomery_calc_normalization(mp_int *a, const mp_int *b); + +/* computes x/R == x (mod N) via Montgomery Reduction */ +int mp_montgomery_reduce(mp_int *a, const mp_int *m, mp_digit mp); + +/* returns 1 if a is a valid DR modulus */ +int mp_dr_is_modulus(mp_int *a); + +/* sets the value of "d" required for mp_dr_reduce */ +void mp_dr_setup(const mp_int *a, mp_digit *d); + +/* reduces a modulo b using the Diminished Radix method */ +int mp_dr_reduce(mp_int *a, const mp_int *b, mp_digit mp); + +/* returns true if a can be reduced with mp_reduce_2k */ +int mp_reduce_is_2k(mp_int *a); + +/* determines k value for 2k reduction */ +int mp_reduce_2k_setup(const mp_int *a, mp_digit *d); + +/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */ +int mp_reduce_2k(mp_int *a, const mp_int *n, mp_digit d); + +/* d = a**b (mod c) */ +int mp_exptmod(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d); + +/* ---> Primes <--- */ + +/* number of primes */ +#define PRIME_SIZE 256 + +/* result=1 if a is divisible by one of the first PRIME_SIZE primes */ +int mp_prime_is_divisible(const mp_int *a, int *result); + +/* performs one Fermat test of "a" using base "b". + * Sets result to 0 if composite or 1 if probable prime + */ +int mp_prime_fermat(mp_int *a, mp_int *b, int *result); + +/* performs one Miller-Rabin test of "a" using base "b". + * Sets result to 0 if composite or 1 if probable prime + */ +int mp_prime_miller_rabin(mp_int *a, const mp_int *b, int *result); + +/* This gives [for a given bit size] the number of trials required + * such that Miller-Rabin gives a prob of failure lower than 2^-96 + */ +int mp_prime_rabin_miller_trials(int size); + +/* performs t rounds of Miller-Rabin on "a" using the first + * t prime bases. Also performs an initial sieve of trial + * division. Determines if "a" is prime with probability + * of error no more than (1/4)**t. + * + * Sets result to 1 if probably prime, 0 otherwise + */ +int mp_prime_is_prime(mp_int *a, int t, int *result); + +/* finds the next prime after the number "a" using "t" trials + * of Miller-Rabin. + * + * bbs_style = 1 means the prime must be congruent to 3 mod 4 + */ +int mp_prime_next_prime(mp_int *a, int t, int bbs_style); + +/* makes a truly random prime of a given size (bytes), + * call with bbs = 1 if you want it to be congruent to 3 mod 4 + * + * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can + * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself + * so it can be NULL + * + * The prime generated will be larger than 2^(8*size). + */ +#define mp_prime_random(a, t, size, bbs, cb, dat) mp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?LTM_PRIME_BBS:0, cb, dat) + +/* makes a truly random prime of a given size (bits), + * + * Flags are as follows: + * + * LTM_PRIME_BBS - make prime congruent to 3 mod 4 + * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS) + * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero + * LTM_PRIME_2MSB_ON - make the 2nd highest bit one + * + * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can + * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself + * so it can be NULL + * + */ +int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat); + +/* ---> radix conversion <--- */ +int mp_count_bits(const mp_int *a); + +int mp_unsigned_bin_size(const mp_int *a); +int mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c); +int mp_to_unsigned_bin(const mp_int *a, unsigned char *b); + +int mp_signed_bin_size(const mp_int *a); +int mp_read_signed_bin(mp_int *a, unsigned char *b, int c); +int mp_to_signed_bin(mp_int *a, unsigned char *b); + +int mp_read_radix(mp_int *a, char *str, int radix); +int mp_toradix(mp_int *a, char *str, int radix); +int mp_toradix_n(mp_int * a, char *str, int radix, int maxlen); +int mp_radix_size(mp_int *a, int radix, int *size); + +int mp_fread(mp_int *a, int radix, FILE *stream); +int mp_fwrite(mp_int *a, int radix, FILE *stream); + +#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) +#define mp_raw_size(mp) mp_signed_bin_size(mp) +#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) +#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) +#define mp_mag_size(mp) mp_unsigned_bin_size(mp) +#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) + +#define mp_tobinary(M, S) mp_toradix((M), (S), 2) +#define mp_tooctal(M, S) mp_toradix((M), (S), 8) +#define mp_todecimal(M, S) mp_toradix((M), (S), 10) +#define mp_tohex(M, S) mp_toradix((M), (S), 16) + +/* lowlevel functions, do not call! */ +int s_mp_add(mp_int *a, mp_int *b, mp_int *c); +int s_mp_sub(const mp_int *a, const mp_int *b, mp_int *c); +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) +int fast_s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs); +int s_mp_mul_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs); +int fast_s_mp_mul_high_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs); +int s_mp_mul_high_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs); +int fast_s_mp_sqr(const mp_int *a, mp_int *b); +int s_mp_sqr(const mp_int *a, mp_int *b); +int mp_karatsuba_mul(const mp_int *a, const mp_int *b, mp_int *c); +int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c); +int mp_karatsuba_sqr(const mp_int *a, mp_int *b); +int mp_toom_sqr(mp_int *a, mp_int *b); +int fast_mp_invmod(const mp_int *a, mp_int *b, mp_int *c); +int mp_invmod_slow (const mp_int * a, mp_int * b, mp_int * c); +int fast_mp_montgomery_reduce(mp_int *a, const mp_int *m, mp_digit mp); +int mp_exptmod_fast(const mp_int *G, const mp_int *X, mp_int *P, mp_int *Y, int mode); +int s_mp_exptmod (const mp_int * G, const mp_int * X, mp_int * P, mp_int * Y); +void bn_reverse(unsigned char *s, int len); + +extern const char *mp_s_rmap; + +#define PK_PRIVATE 0 /* PK private keys */ +#define PK_PUBLIC 1 /* PK public keys */ + +/* Min and Max RSA key sizes (in bits) */ +#define MIN_RSA_SIZE 384 +#define MAX_RSA_SIZE 16384 + +typedef struct Rsa_key { + int type; + mp_int e, d, N, p, q, qP, dP, dQ; +} rsa_key; + +int rsa_make_key(int size, long e, rsa_key *key); + +int rsa_exptmod(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, int which, + rsa_key *key); + +void rsa_free(rsa_key *key); + +#endif /* __WINE_TOMCRYPT_H_ */ diff --git a/reactos/dll/win32/rsaenh/version.rc b/reactos/dll/win32/rsaenh/version.rc new file mode 100644 index 00000000000..9fc81a5cb8f --- /dev/null +++ b/reactos/dll/win32/rsaenh/version.rc @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2007 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define WINE_FILEDESCRIPTION_STR "Wine rsaenh" +#define WINE_FILENAME_STR "rsaenh.dll" +#define WINE_FILEVERSION 5,1,2600,2180 +#define WINE_FILEVERSION_STR "5.1.2600.2180" +#define WINE_PRODUCTVERSION 5,1,2600,2180 +#define WINE_PRODUCTVERSION_STR "5.1.2600.2180" + +#include "wine/wine_common_ver.rc"