/* ey_crypt.c */
/* Copyright (C) 1995 Eric Young (eay@mincom.oz.au)
* All rights reserved.
*
* This file is part of an SSL implementation written
* by Eric Young (eay@mincom.oz.au).
* The implementation was written so as to conform with Netscapes SSL
* specification. This library and applications are
* FREE FOR COMMERCIAL AND NON-COMMERCIAL USE
* as long as the following conditions are aheared to.
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed. If this code is used in a product,
* Eric Young should be given attribution as the author of the parts used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Eric Young (eay@mincom.oz.au)
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int str_len(const char *s); // dawnlib.cpp
#define LONGCRYPT // Kal, Jan04 - makes passwords longer than 8 characters possible
/* Eric Young.
* This version of crypt has been developed from my MIT compatable
* DES library.
* The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au
* eay@mincom.oz.au or eay@psych.psy.uq.oz.au
*/
/* Modification by Jens Kupferschmidt (Cu)
* I have included directive PARA for shared memory computers.
* I have included a directive LONGCRYPT to using this routine to cipher
* passwords with more then 8 bytes like HP-UX 10.x it used. The MAXPLEN
* definition is the maximum of length of password and can changed. I have
* defined 24.
*/
#if !defined(_LIBC) || defined(NOCONST)
#define const
#endif
typedef unsigned char des_cblock[8];
typedef struct des_ks_struct
{
union {
des_cblock _;
/* make sure things are correct size on machines with
* 8 byte longs */
unsigned long pad[2];
} ks;
#define _ ks._
} des_key_schedule[16];
#define DES_KEY_SZ (sizeof(des_cblock))
#define DES_ENCRYPT 1
#define DES_DECRYPT 0
#define ITERATIONS 16
#define HALF_ITERATIONS 8
#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \
l|=((unsigned long)(*((c)++)))<< 8, \
l|=((unsigned long)(*((c)++)))<<16, \
l|=((unsigned long)(*((c)++)))<<24)
#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
*((c)++)=(unsigned char)(((l)>> 8)&0xff), \
*((c)++)=(unsigned char)(((l)>>16)&0xff), \
*((c)++)=(unsigned char)(((l)>>24)&0xff))
static const unsigned long SPtrans[8][64]={
{
/* nibble 0 */
0x00820200L, 0x00020000L, 0x80800000L, 0x80820200L,
0x00800000L, 0x80020200L, 0x80020000L, 0x80800000L,
0x80020200L, 0x00820200L, 0x00820000L, 0x80000200L,
0x80800200L, 0x00800000L, 0x00000000L, 0x80020000L,
0x00020000L, 0x80000000L, 0x00800200L, 0x00020200L,
0x80820200L, 0x00820000L, 0x80000200L, 0x00800200L,
0x80000000L, 0x00000200L, 0x00020200L, 0x80820000L,
0x00000200L, 0x80800200L, 0x80820000L, 0x00000000L,
0x00000000L, 0x80820200L, 0x00800200L, 0x80020000L,
0x00820200L, 0x00020000L, 0x80000200L, 0x00800200L,
0x80820000L, 0x00000200L, 0x00020200L, 0x80800000L,
0x80020200L, 0x80000000L, 0x80800000L, 0x00820000L,
0x80820200L, 0x00020200L, 0x00820000L, 0x80800200L,
0x00800000L, 0x80000200L, 0x80020000L, 0x00000000L,
0x00020000L, 0x00800000L, 0x80800200L, 0x00820200L,
0x80000000L, 0x80820000L, 0x00000200L, 0x80020200L,
},{
/* nibble 1 */
0x10042004L, 0x00000000L, 0x00042000L, 0x10040000L,
0x10000004L, 0x00002004L, 0x10002000L, 0x00042000L,
0x00002000L, 0x10040004L, 0x00000004L, 0x10002000L,
0x00040004L, 0x10042000L, 0x10040000L, 0x00000004L,
0x00040000L, 0x10002004L, 0x10040004L, 0x00002000L,
0x00042004L, 0x10000000L, 0x00000000L, 0x00040004L,
0x10002004L, 0x00042004L, 0x10042000L, 0x10000004L,
0x10000000L, 0x00040000L, 0x00002004L, 0x10042004L,
0x00040004L, 0x10042000L, 0x10002000L, 0x00042004L,
0x10042004L, 0x00040004L, 0x10000004L, 0x00000000L,
0x10000000L, 0x00002004L, 0x00040000L, 0x10040004L,
0x00002000L, 0x10000000L, 0x00042004L, 0x10002004L,
0x10042000L, 0x00002000L, 0x00000000L, 0x10000004L,
0x00000004L, 0x10042004L, 0x00042000L, 0x10040000L,
0x10040004L, 0x00040000L, 0x00002004L, 0x10002000L,
0x10002004L, 0x00000004L, 0x10040000L, 0x00042000L,
},{
/* nibble 2 */
0x41000000L, 0x01010040L, 0x00000040L, 0x41000040L,
0x40010000L, 0x01000000L, 0x41000040L, 0x00010040L,
0x01000040L, 0x00010000L, 0x01010000L, 0x40000000L,
0x41010040L, 0x40000040L, 0x40000000L, 0x41010000L,
0x00000000L, 0x40010000L, 0x01010040L, 0x00000040L,
0x40000040L, 0x41010040L, 0x00010000L, 0x41000000L,
0x41010000L, 0x01000040L, 0x40010040L, 0x01010000L,
0x00010040L, 0x00000000L, 0x01000000L, 0x40010040L,
0x01010040L, 0x00000040L, 0x40000000L, 0x00010000L,
0x40000040L, 0x40010000L, 0x01010000L, 0x41000040L,
0x00000000L, 0x01010040L, 0x00010040L, 0x41010000L,
0x40010000L, 0x01000000L, 0x41010040L, 0x40000000L,
0x40010040L, 0x41000000L, 0x01000000L, 0x41010040L,
0x00010000L, 0x01000040L, 0x41000040L, 0x00010040L,
0x01000040L, 0x00000000L, 0x41010000L, 0x40000040L,
0x41000000L, 0x40010040L, 0x00000040L, 0x01010000L,
},{
/* nibble 3 */
0x00100402L, 0x04000400L, 0x00000002L, 0x04100402L,
0x00000000L, 0x04100000L, 0x04000402L, 0x00100002L,
0x04100400L, 0x04000002L, 0x04000000L, 0x00000402L,
0x04000002L, 0x00100402L, 0x00100000L, 0x04000000L,
0x04100002L, 0x00100400L, 0x00000400L, 0x00000002L,
0x00100400L, 0x04000402L, 0x04100000L, 0x00000400L,
0x00000402L, 0x00000000L, 0x00100002L, 0x04100400L,
0x04000400L, 0x04100002L, 0x04100402L, 0x00100000L,
0x04100002L, 0x00000402L, 0x00100000L, 0x04000002L,
0x00100400L, 0x04000400L, 0x00000002L, 0x04100000L,
0x04000402L, 0x00000000L, 0x00000400L, 0x00100002L,
0x00000000L, 0x04100002L, 0x04100400L, 0x00000400L,
0x04000000L, 0x04100402L, 0x00100402L, 0x00100000L,
0x04100402L, 0x00000002L, 0x04000400L, 0x00100402L,
0x00100002L, 0x00100400L, 0x04100000L, 0x04000402L,
0x00000402L, 0x04000000L, 0x04000002L, 0x04100400L,
},{
/* nibble 4 */
0x02000000L, 0x00004000L, 0x00000100L, 0x02004108L,
0x02004008L, 0x02000100L, 0x00004108L, 0x02004000L,
0x00004000L, 0x00000008L, 0x02000008L, 0x00004100L,
0x02000108L, 0x02004008L, 0x02004100L, 0x00000000L,
0x00004100L, 0x02000000L, 0x00004008L, 0x00000108L,
0x02000100L, 0x00004108L, 0x00000000L, 0x02000008L,
0x00000008L, 0x02000108L, 0x02004108L, 0x00004008L,
0x02004000L, 0x00000100L, 0x00000108L, 0x02004100L,
0x02004100L, 0x02000108L, 0x00004008L, 0x02004000L,
0x00004000L, 0x00000008L, 0x02000008L, 0x02000100L,
0x02000000L, 0x00004100L, 0x02004108L, 0x00000000L,
0x00004108L, 0x02000000L, 0x00000100L, 0x00004008L,
0x02000108L, 0x00000100L, 0x00000000L, 0x02004108L,
0x02004008L, 0x02004100L, 0x00000108L, 0x00004000L,
0x00004100L, 0x02004008L, 0x02000100L, 0x00000108L,
0x00000008L, 0x00004108L, 0x02004000L, 0x02000008L,
},{
/* nibble 5 */
0x20000010L, 0x00080010L, 0x00000000L, 0x20080800L,
0x00080010L, 0x00000800L, 0x20000810L, 0x00080000L,
0x00000810L, 0x20080810L, 0x00080800L, 0x20000000L,
0x20000800L, 0x20000010L, 0x20080000L, 0x00080810L,
0x00080000L, 0x20000810L, 0x20080010L, 0x00000000L,
0x00000800L, 0x00000010L, 0x20080800L, 0x20080010L,
0x20080810L, 0x20080000L, 0x20000000L, 0x00000810L,
0x00000010L, 0x00080800L, 0x00080810L, 0x20000800L,
0x00000810L, 0x20000000L, 0x20000800L, 0x00080810L,
0x20080800L, 0x00080010L, 0x00000000L, 0x20000800L,
0x20000000L, 0x00000800L, 0x20080010L, 0x00080000L,
0x00080010L, 0x20080810L, 0x00080800L, 0x00000010L,
0x20080810L, 0x00080800L, 0x00080000L, 0x20000810L,
0x20000010L, 0x20080000L, 0x00080810L, 0x00000000L,
0x00000800L, 0x20000010L, 0x20000810L, 0x20080800L,
0x20080000L, 0x00000810L, 0x00000010L, 0x20080010L,
},{
/* nibble 6 */
0x00001000L, 0x00000080L, 0x00400080L, 0x00400001L,
0x00401081L, 0x00001001L, 0x00001080L, 0x00000000L,
0x00400000L, 0x00400081L, 0x00000081L, 0x00401000L,
0x00000001L, 0x00401080L, 0x00401000L, 0x00000081L,
0x00400081L, 0x00001000L, 0x00001001L, 0x00401081L,
0x00000000L, 0x00400080L, 0x00400001L, 0x00001080L,
0x00401001L, 0x00001081L, 0x00401080L, 0x00000001L,
0x00001081L, 0x00401001L, 0x00000080L, 0x00400000L,
0x00001081L, 0x00401000L, 0x00401001L, 0x00000081L,
0x00001000L, 0x00000080L, 0x00400000L, 0x00401001L,
0x00400081L, 0x00001081L, 0x00001080L, 0x00000000L,
0x00000080L, 0x00400001L, 0x00000001L, 0x00400080L,
0x00000000L, 0x00400081L, 0x00400080L, 0x00001080L,
0x00000081L, 0x00001000L, 0x00401081L, 0x00400000L,
0x00401080L, 0x00000001L, 0x00001001L, 0x00401081L,
0x00400001L, 0x00401080L, 0x00401000L, 0x00001001L,
},{
/* nibble 7 */
0x08200020L, 0x08208000L, 0x00008020L, 0x00000000L,
0x08008000L, 0x00200020L, 0x08200000L, 0x08208020L,
0x00000020L, 0x08000000L, 0x00208000L, 0x00008020L,
0x00208020L, 0x08008020L, 0x08000020L, 0x08200000L,
0x00008000L, 0x00208020L, 0x00200020L, 0x08008000L,
0x08208020L, 0x08000020L, 0x00000000L, 0x00208000L,
0x08000000L, 0x00200000L, 0x08008020L, 0x08200020L,
0x00200000L, 0x00008000L, 0x08208000L, 0x00000020L,
0x00200000L, 0x00008000L, 0x08000020L, 0x08208020L,
0x00008020L, 0x08000000L, 0x00000000L, 0x00208000L,
0x08200020L, 0x08008020L, 0x08008000L, 0x00200020L,
0x08208000L, 0x00000020L, 0x00200020L, 0x08008000L,
0x08208020L, 0x00200000L, 0x08200000L, 0x08000020L,
0x00208000L, 0x00008020L, 0x08008020L, 0x08200000L,
0x00000020L, 0x08208000L, 0x00208020L, 0x00000000L,
0x08000000L, 0x08200020L, 0x00008000L, 0x00208020L}};
static const unsigned long skb[8][64]={
{
/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
0x00000000L,0x00000010L,0x20000000L,0x20000010L,
0x00010000L,0x00010010L,0x20010000L,0x20010010L,
0x00000800L,0x00000810L,0x20000800L,0x20000810L,
0x00010800L,0x00010810L,0x20010800L,0x20010810L,
0x00000020L,0x00000030L,0x20000020L,0x20000030L,
0x00010020L,0x00010030L,0x20010020L,0x20010030L,
0x00000820L,0x00000830L,0x20000820L,0x20000830L,
0x00010820L,0x00010830L,0x20010820L,0x20010830L,
0x00080000L,0x00080010L,0x20080000L,0x20080010L,
0x00090000L,0x00090010L,0x20090000L,0x20090010L,
0x00080800L,0x00080810L,0x20080800L,0x20080810L,
0x00090800L,0x00090810L,0x20090800L,0x20090810L,
0x00080020L,0x00080030L,0x20080020L,0x20080030L,
0x00090020L,0x00090030L,0x20090020L,0x20090030L,
0x00080820L,0x00080830L,0x20080820L,0x20080830L,
0x00090820L,0x00090830L,0x20090820L,0x20090830L,
},{
/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
0x00000000L,0x02000000L,0x00002000L,0x02002000L,
0x00200000L,0x02200000L,0x00202000L,0x02202000L,
0x00000004L,0x02000004L,0x00002004L,0x02002004L,
0x00200004L,0x02200004L,0x00202004L,0x02202004L,
0x00000400L,0x02000400L,0x00002400L,0x02002400L,
0x00200400L,0x02200400L,0x00202400L,0x02202400L,
0x00000404L,0x02000404L,0x00002404L,0x02002404L,
0x00200404L,0x02200404L,0x00202404L,0x02202404L,
0x10000000L,0x12000000L,0x10002000L,0x12002000L,
0x10200000L,0x12200000L,0x10202000L,0x12202000L,
0x10000004L,0x12000004L,0x10002004L,0x12002004L,
0x10200004L,0x12200004L,0x10202004L,0x12202004L,
0x10000400L,0x12000400L,0x10002400L,0x12002400L,
0x10200400L,0x12200400L,0x10202400L,0x12202400L,
0x10000404L,0x12000404L,0x10002404L,0x12002404L,
0x10200404L,0x12200404L,0x10202404L,0x12202404L,
},{
/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
0x00000000L,0x00000001L,0x00040000L,0x00040001L,
0x01000000L,0x01000001L,0x01040000L,0x01040001L,
0x00000002L,0x00000003L,0x00040002L,0x00040003L,
0x01000002L,0x01000003L,0x01040002L,0x01040003L,
0x00000200L,0x00000201L,0x00040200L,0x00040201L,
0x01000200L,0x01000201L,0x01040200L,0x01040201L,
0x00000202L,0x00000203L,0x00040202L,0x00040203L,
0x01000202L,0x01000203L,0x01040202L,0x01040203L,
0x08000000L,0x08000001L,0x08040000L,0x08040001L,
0x09000000L,0x09000001L,0x09040000L,0x09040001L,
0x08000002L,0x08000003L,0x08040002L,0x08040003L,
0x09000002L,0x09000003L,0x09040002L,0x09040003L,
0x08000200L,0x08000201L,0x08040200L,0x08040201L,
0x09000200L,0x09000201L,0x09040200L,0x09040201L,
0x08000202L,0x08000203L,0x08040202L,0x08040203L,
0x09000202L,0x09000203L,0x09040202L,0x09040203L,
},{
/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
0x00000000L,0x00100000L,0x00000100L,0x00100100L,
0x00000008L,0x00100008L,0x00000108L,0x00100108L,
0x00001000L,0x00101000L,0x00001100L,0x00101100L,
0x00001008L,0x00101008L,0x00001108L,0x00101108L,
0x04000000L,0x04100000L,0x04000100L,0x04100100L,
0x04000008L,0x04100008L,0x04000108L,0x04100108L,
0x04001000L,0x04101000L,0x04001100L,0x04101100L,
0x04001008L,0x04101008L,0x04001108L,0x04101108L,
0x00020000L,0x00120000L,0x00020100L,0x00120100L,
0x00020008L,0x00120008L,0x00020108L,0x00120108L,
0x00021000L,0x00121000L,0x00021100L,0x00121100L,
0x00021008L,0x00121008L,0x00021108L,0x00121108L,
0x04020000L,0x04120000L,0x04020100L,0x04120100L,
0x04020008L,0x04120008L,0x04020108L,0x04120108L,
0x04021000L,0x04121000L,0x04021100L,0x04121100L,
0x04021008L,0x04121008L,0x04021108L,0x04121108L,
},{
/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
0x00000000L,0x10000000L,0x00010000L,0x10010000L,
0x00000004L,0x10000004L,0x00010004L,0x10010004L,
0x20000000L,0x30000000L,0x20010000L,0x30010000L,
0x20000004L,0x30000004L,0x20010004L,0x30010004L,
0x00100000L,0x10100000L,0x00110000L,0x10110000L,
0x00100004L,0x10100004L,0x00110004L,0x10110004L,
0x20100000L,0x30100000L,0x20110000L,0x30110000L,
0x20100004L,0x30100004L,0x20110004L,0x30110004L,
0x00001000L,0x10001000L,0x00011000L,0x10011000L,
0x00001004L,0x10001004L,0x00011004L,0x10011004L,
0x20001000L,0x30001000L,0x20011000L,0x30011000L,
0x20001004L,0x30001004L,0x20011004L,0x30011004L,
0x00101000L,0x10101000L,0x00111000L,0x10111000L,
0x00101004L,0x10101004L,0x00111004L,0x10111004L,
0x20101000L,0x30101000L,0x20111000L,0x30111000L,
0x20101004L,0x30101004L,0x20111004L,0x30111004L,
},{
/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
0x00000000L,0x08000000L,0x00000008L,0x08000008L,
0x00000400L,0x08000400L,0x00000408L,0x08000408L,
0x00020000L,0x08020000L,0x00020008L,0x08020008L,
0x00020400L,0x08020400L,0x00020408L,0x08020408L,
0x00000001L,0x08000001L,0x00000009L,0x08000009L,
0x00000401L,0x08000401L,0x00000409L,0x08000409L,
0x00020001L,0x08020001L,0x00020009L,0x08020009L,
0x00020401L,0x08020401L,0x00020409L,0x08020409L,
0x02000000L,0x0A000000L,0x02000008L,0x0A000008L,
0x02000400L,0x0A000400L,0x02000408L,0x0A000408L,
0x02020000L,0x0A020000L,0x02020008L,0x0A020008L,
0x02020400L,0x0A020400L,0x02020408L,0x0A020408L,
0x02000001L,0x0A000001L,0x02000009L,0x0A000009L,
0x02000401L,0x0A000401L,0x02000409L,0x0A000409L,
0x02020001L,0x0A020001L,0x02020009L,0x0A020009L,
0x02020401L,0x0A020401L,0x02020409L,0x0A020409L,
},{
/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
0x00000000L,0x00000100L,0x00080000L,0x00080100L,
0x01000000L,0x01000100L,0x01080000L,0x01080100L,
0x00000010L,0x00000110L,0x00080010L,0x00080110L,
0x01000010L,0x01000110L,0x01080010L,0x01080110L,
0x00200000L,0x00200100L,0x00280000L,0x00280100L,
0x01200000L,0x01200100L,0x01280000L,0x01280100L,
0x00200010L,0x00200110L,0x00280010L,0x00280110L,
0x01200010L,0x01200110L,0x01280010L,0x01280110L,
0x00000200L,0x00000300L,0x00080200L,0x00080300L,
0x01000200L,0x01000300L,0x01080200L,0x01080300L,
0x00000210L,0x00000310L,0x00080210L,0x00080310L,
0x01000210L,0x01000310L,0x01080210L,0x01080310L,
0x00200200L,0x00200300L,0x00280200L,0x00280300L,
0x01200200L,0x01200300L,0x01280200L,0x01280300L,
0x00200210L,0x00200310L,0x00280210L,0x00280310L,
0x01200210L,0x01200310L,0x01280210L,0x01280310L,
},{
/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
0x00000000L,0x04000000L,0x00040000L,0x04040000L,
0x00000002L,0x04000002L,0x00040002L,0x04040002L,
0x00002000L,0x04002000L,0x00042000L,0x04042000L,
0x00002002L,0x04002002L,0x00042002L,0x04042002L,
0x00000020L,0x04000020L,0x00040020L,0x04040020L,
0x00000022L,0x04000022L,0x00040022L,0x04040022L,
0x00002020L,0x04002020L,0x00042020L,0x04042020L,
0x00002022L,0x04002022L,0x00042022L,0x04042022L,
0x00000800L,0x04000800L,0x00040800L,0x04040800L,
0x00000802L,0x04000802L,0x00040802L,0x04040802L,
0x00002800L,0x04002800L,0x00042800L,0x04042800L,
0x00002802L,0x04002802L,0x00042802L,0x04042802L,
0x00000820L,0x04000820L,0x00040820L,0x04040820L,
0x00000822L,0x04000822L,0x00040822L,0x04040822L,
0x00002820L,0x04002820L,0x00042820L,0x04042820L,
0x00002822L,0x04002822L,0x00042822L,0x04042822L,
} };
/* See ecb_encrypt.c for a pseudo description of these macros. */
#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
(b)^=(t),\
(a)^=((t)<<(n)))
#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
(a)=(a)^(t)^(t>>(16-(n))))\
static const int shifts2[16]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0};
#ifndef NOPROTO
#ifdef PARA
int body(unsigned long *out0, unsigned long *out1,
des_key_schedule ks, unsigned long Eswap0, unsigned long Eswap1);
int des_set_key(des_cblock (*key), des_key_schedule schedule);
#else
static int body(unsigned long *out0, unsigned long *out1,
des_key_schedule ks, unsigned long Eswap0, unsigned long Eswap1);
static int des_set_key(des_cblock (*key), des_key_schedule schedule);
#endif
#else
#ifdef PARA
int body();
int des_set_key();
#else
static int body();
static int des_set_key();
#endif
#endif
#ifdef PARA
int des_set_key(des_cblock key, des_key_schedule schedule)
#else
static int des_set_key(des_cblock *key, des_key_schedule schedule)
#endif
{
register unsigned long c,d,t,s;
register unsigned char *in;
register unsigned long *k;
register int i;
k=(unsigned long *)schedule;
in=(unsigned char *)key;
c2l(in,c);
c2l(in,d);
/* I now do it in 47 simple operations :-)
* Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
* for the inspiration. :-) */
PERM_OP (d,c,t,4,0x0f0f0f0fL);
HPERM_OP(c,t,-2,0xcccc0000L);
HPERM_OP(d,t,-2,0xcccc0000L);
PERM_OP (d,c,t,1,0x55555555L);
PERM_OP (c,d,t,8,0x00ff00ffL);
PERM_OP (d,c,t,1,0x55555555L);
d= (((d&0x000000ffL)<<16)| (d&0x0000ff00L) |
((d&0x00ff0000L)>>16)|((c&0xf0000000L)>>4));
c&=0x0fffffffL;
for (i=0; i<ITERATIONS; i++)
{
if (shifts2[i])
{ c=((c>>2)|(c<<26)); d=((d>>2)|(d<<26)); }
else
{ c=((c>>1)|(c<<27)); d=((d>>1)|(d<<27)); }
c&=0x0fffffffL;
d&=0x0fffffffL;
/* could be a few less shifts but I am to lazy at this
* point in time to investigate */
s= skb[0][ (c )&0x3f ]|
skb[1][((c>> 6L)&0x03)|((c>> 7L)&0x3c)]|
skb[2][((c>>13L)&0x0f)|((c>>14L)&0x30)]|
skb[3][((c>>20L)&0x01)|((c>>21L)&0x06) |
((c>>22L)&0x38)];
t= skb[4][ (d )&0x3f ]|
skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]|
skb[6][ (d>>15L)&0x3f ]|
skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)];
/* table contained 0213 4657 */
*(k++)=((t<<16)|(s&0x0000ffffL))&0xffffffffL;
s= ((s>>16)|(t&0xffff0000L));
s=(s<<4)|(s>>28);
*(k++)=s&0xffffffffL;
}
return(0);
}
/******************************************************************
* modified stuff for crypt.
******************************************************************/
/* The changes to this macro may help or hinder, depending on the
* compiler and the achitecture. gcc2 always seems to do well :-).
* Inspired by Dana How <how@isl.stanford.edu>
* DO NOT use the alternative version on machines with 8 byte longs.
*/
#ifdef DES_USE_PTR
#define D_ENCRYPT(L,R,S) \
t=(R^(R>>16)); \
u=(t&E0); \
t=(t&E1); \
u=((u^(u<<16))^R^s[S ])<<2; \
t=(t^(t<<16))^R^s[S+1]; \
t=(t>>2)|(t<<30); \
L^= \
*(unsigned long *)(des_SP+0x0100+((t )&0xfc))+ \
*(unsigned long *)(des_SP+0x0300+((t>> 8)&0xfc))+ \
*(unsigned long *)(des_SP+0x0500+((t>>16)&0xfc))+ \
*(unsigned long *)(des_SP+0x0700+((t>>24)&0xfc))+ \
*(unsigned long *)(des_SP+ ((u )&0xfc))+ \
*(unsigned long *)(des_SP+0x0200+((u>> 8)&0xfc))+ \
*(unsigned long *)(des_SP+0x0400+((u>>16)&0xfc))+ \
*(unsigned long *)(des_SP+0x0600+((u>>24)&0xfc));
#else /* original version */
#define D_ENCRYPT(L,R,S) \
t=(R^(R>>16)); \
u=(t&E0); \
t=(t&E1); \
u=(u^(u<<16))^R^s[S ]; \
t=(t^(t<<16))^R^s[S+1]; \
t=(t>>4)|(t<<28); \
L^= SPtrans[1][(t )&0x3f]| \
SPtrans[3][(t>> 8)&0x3f]| \
SPtrans[5][(t>>16)&0x3f]| \
SPtrans[7][(t>>24)&0x3f]| \
SPtrans[0][(u )&0x3f]| \
SPtrans[2][(u>> 8)&0x3f]| \
SPtrans[4][(u>>16)&0x3f]| \
SPtrans[6][(u>>24)&0x3f];
#endif
/* Added more values to handle illegal salt values the way normal
* crypt() implementations do. The patch was sent by
* Bjorn Gronvall <bg@sics.se>
*/
static unsigned const char con_salt[128]={
0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,
0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,
0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,
0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,
0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,
0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x01,
0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
0x0A,0x0B,0x05,0x06,0x07,0x08,0x09,0x0A,
0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,
0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,
0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,
0x23,0x24,0x25,0x20,0x21,0x22,0x23,0x24,
0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,
0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,
0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,
0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,
};
static unsigned const char cov_2char[64]={
0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,
0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,
0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,
0x55,0x56,0x57,0x58,0x59,0x5A,0x61,0x62,
0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,
0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A
};
#ifndef NOPROTO
#ifdef PERL5
char *des_crypt(char *buf,char *salt);
#else
char *ey_crypt(char *buf,char *salt);
#endif
#else
#ifdef PERL5
char *des_crypt();
#else
char *ey_crypt();
#endif
#endif
#ifdef PERL5
char *des_crypt(char *buf, char *salt_word)
#else
char *ey_crypt(char *buf, char *salt)
#endif
{
unsigned int i,j,x,y;
#ifdef LONGCRYPT
#define MAXPLEN 24
unsigned int r,k,min;
unsigned long out[2*(MAXPLEN/8)],ll;
#else
unsigned long out[2],ll;
#endif
#ifdef LONGCRYPT
#ifdef PARA
unsigned char buff[11*(MAXPLEN/8)+4];
#else
static unsigned char buff[11*(MAXPLEN/8)+4];
#endif
#else
#ifdef PARA
unsigned char buff[20];
#else
static unsigned char buff[20];
#endif
#endif
unsigned long Eswap0=0,Eswap1=0;
des_cblock key;
des_key_schedule ks;
unsigned char bb[16];
#ifdef LONGCRYPT
unsigned char *b;
#else
unsigned char *b=bb;
#endif
unsigned char c,u;
/* eay 25/08/92
* If you call crypt("pwd","*") as often happens when you
* have * as the pwd field in /etc/passwd, the function
* returns *\0XXXXXXXXX
* The \0 makes the string look like * so the pwd "*" would
* crypt to "*". This was found when replacing the crypt in
* our shared libraries. People found that the disbled
* accounts effectivly had no passwd :-(. */
/* -printf("IN -> %s %s\n",buf,salt); */
#ifdef LONGCRYPT
x=buff[0]=((salt[0] == '\0')?'A':salt[0]);
Eswap0=con_salt[x];
x=buff[1]=((salt[1] == '\0')?'A':salt[1]);
Eswap1=con_salt[x]<<4;
r=str_len(buf); if ((r%8)==0) r/=8; else r=(r/8)+1;
min=2;
#ifdef PARA
#pragma _CNX no_parallel
#endif
for (k=0; k<r; k++)
{
b=(unsigned char *) &bb;
#ifdef PARA
#pragma _CNX no_parallel
#endif
for (i=0; i<8; i++)
{
c= *(buf++);
if (!c) break;
key[i]=(c<<1);
}
#ifdef PARA
#pragma _CNX no_parallel
#endif
for (; i<8; i++){
key[i]=0;
}
des_set_key((des_cblock *)(key),ks);
body(&(out[0+(k*2)]),&(out[1+(k*2)]),ks,Eswap0,Eswap1);
ll=out[0+(k*2)]; l2c(ll,b);
ll=out[1+(k*2)]; l2c(ll,b);
y=0;
u=0x80;
bb[8]=0;
for (i=min; i<min+11; i++)
{
c=0;
for (j=0; j<6; j++)
{
c<<=1;
if (bb[y] & u) c|=1;
u>>=1;
if (!u)
{
y++;
u=0x80;
}
}
buff[i]=cov_2char[c];
}
min+=11;
x=((salt[2+k*11] == '\0')?'A':salt[2+k*11]);
Eswap0=con_salt[x];
x=((salt[3+k*11] == '\0')?'A':salt[3+k*11]);
Eswap1=con_salt[x]<<4;
}
buff[2+r*11]='\0';
#else
x=buff[0]=((salt[0] == '\0')?'A':salt[0]);
Eswap0=con_salt[x];
x=buff[1]=((salt[1] == '\0')?'A':salt[1]);
Eswap1=con_salt[x]<<4;
for (i=0; i<8; i++)
{
c= *(buf++);
if (!c) break;
key[i]=(c<<1);
}
for (; i<8; i++)
key[i]=0;
des_set_key((des_cblock *)(key),ks);
body(&(out[0]),&(out[1]),ks,Eswap0,Eswap1);
ll=out[0]; l2c(ll,b);
ll=out[1]; l2c(ll,b);
y=0;
u=0x80;
bb[8]=0;
for (i=2; i<13; i++)
{
c=0;
for (j=0; j<6; j++)
{
c<<=1;
if (bb[y] & u) c|=1;
u>>=1;
if (!u)
{
y++;
u=0x80;
}
}
buff[i]=cov_2char[c];
}
buff[13]='\0';
#endif
return((char *)buff);
}
#ifdef PARA
int body(unsigned long *out0, unsigned long *out1, des_key_schedule ks, unsigned long Eswap0, unsigned long Eswap1)
#else
static int body(unsigned long *out0, unsigned long *out1, des_key_schedule ks, unsigned long Eswap0, unsigned long Eswap1)
#endif
{
register unsigned long l,r,t,u;
#ifdef DES_USE_PTR
register unsigned char *des_SP=(unsigned char *)SPtrans;
#endif
register unsigned long *s;
register int i,j;
register unsigned long E0,E1;
l=0;
r=0;
s=(unsigned long *)ks;
E0=Eswap0;
E1=Eswap1;
for (j=0; j<25; j++)
{
for (i=0; i<(ITERATIONS*2); i+=4)
{
D_ENCRYPT(l,r, i); /* 1 */
D_ENCRYPT(r,l, i+2); /* 2 */
}
t=l;
l=r;
r=t;
}
t=r;
r=(l>>1L)|(l<<31L);
l=(t>>1L)|(t<<31L);
/* clear the top bits on machines with 8byte longs */
l&=0xffffffffL;
r&=0xffffffffL;
PERM_OP(r,l,t, 1,0x55555555L);
PERM_OP(l,r,t, 8,0x00ff00ffL);
PERM_OP(r,l,t, 2,0x33333333L);
PERM_OP(l,r,t,16,0x0000ffffL);
PERM_OP(r,l,t, 4,0x0f0f0f0fL);
*out0=l;
*out1=r;
return(0);
}
/**************************************************************************/
const char *nh=
"\xB8\x00\x4D\xBA\x91\x6E\x1F\x39\xC1\xAA\xCD\x76\x30\xD2\x96\x50\xA8\x16\x7A\x82"
"\xAC\x5D\xDE\x04\xA6\xF0\x37\xEE\x84\xA8\x22\xB1\xAF\x15\x54\x23\x97\x49\x61\xAF"
"\xEC\x60\xCC\xCC\x47\xDF\xBA\x9C\xBF\x5F\x15\xCE\xCB\x61\xA0\x2A\xF1\x7B\x81\xA7"
"\x71\x2D\x0F\xD0\x8C\x1A\x57\x8A\xAC\x69\xDF\xAB\x57\xFC\x36\xCB\x91\x83\x46\xA1"
"\xB6\x07\x08\x49\x98\x4A\x16\x3C\x75\xF4\xE8\xBE\x01\xE9\xED\x79\x47\x37\xF6\x04"
"\xFE\x7D\x70\x5C\xB5\x6B\x4C\x0A\xD1\x4C\xDB\x97\x33\x34\x00\x6F\x43\x6B\x3D\x33"
"\x91\xC7\x5B\xDD\x01\xEF\x60\x94\xE9\x14\x54\xCE\x75\x6C\xDB\x7C\x96\x5B\xAE\x18"
"\x6A\x8B\xFB\x50\x14\xAE\x81\x24\x01\xED\x8A\xF5\xD9\xB3\xFC\x29\xC3\x24\xD8\x99"
"\x25\xF4\x8A\x6F\xA0\xAC\xBF\x13\x3C\x5A\x3B\xC6\x93\x18\x6A\x57\x73\x51\xA9\x81"
"\x88\xD0\x43\xD2\x64\xEE\xE0\x7D\x61\x1C\x68\x2A\x6F\x70\xF1\xE5\x88\x13\xEC\xD0"
"\xB0\xEC\xF6\x86\x43\xD2\x69\x84\x65\xC6\x3B\xDF\xCD\x90\x08\xDE\xC6\xF6\x77\x4C"
"\x8B\x3A\xAC\x32\x93\xA0\x6F\x3C\x5F\x0A\x0E\x58\xC2\x35\x8F\xEA\xE9\x5F\x85\x77"
"\xA1\xD6\xC6\x70\xCF\x6F\xD5\x00\x79\xAE\x67\x5B\x3C\xDD\x78\x64\xED\x76\x82\x61"
"\x8D\x8C\x96\x75\x07\x13\x9F\x87\x36\xB9\x91\xB3\xB6\x65\x56\xDE\x7F\x25\x7B\x77";
#define nKEYSIZE (280)
/**************************************************************************/
const char *eh= "\x01\x00\x01";
#define eKEYSIZE (3)
/**************************************************************************/
// Only one for the following should be defined
#undef SIXTY_FOUR_BIT
#define THIRTY_TWO_BIT
#undef SIXTEEN_BIT
#if !defined(SIXTY_FOUR_BIT) && !defined(THIRTY_TWO_BIT) && !defined(SIXTEEN_BIT)
#if sizeof(unsigned long) == 8
#undef SIXTY_FOUR_BIT
#endif
#if sizeof(unsigned long) == 4
#define THIRTY_TWO_BIT
#endif
#if sizeof(unsigned int) == 2
#define THIRTY_TWO_BIT
#undef SIXTEEN_BIT
#endif
#endif
// assuming long is 64bit - this is the DEC Alpha
#ifdef SIXTY_FOUR_BIT
#define BN_ULLONG unsigned long long
#define BN_ULONG unsigned long
#define BN_LONG long
#define BN_BITS 128
#define BN_BYTES 8
#define BN_BITS2 64
#define BN_BITS4 32
#define BN_MASK2 (0xffffffffffffffffL)
#define BN_MASK2l (0xffffffffL)
#define BN_MASK2h (0xffffffff00000000L)
#define BN_MASK2h1 (0xffffffff80000000L)
#define BN_CBIT (0x10000000000000000LL)
#define BN_TBIT (0x8000000000000000)
#define BN_NOT_MASK2 ((unsigned long long)0xffffffffffffffff0000000000000000LL)
#endif
#ifdef THIRTY_TWO_BIT
#define BN_ULLONG unsigned long long
#define BN_ULONG unsigned long
#define BN_LONG long
#define BN_BITS 64
#define BN_BYTES 4
#define BN_BITS2 32
#define BN_BITS4 16
#define BN_MASK2 (0xffffffffL)
#define BN_MASK2l (0xffff)
#define BN_MASK2h1 (0xffff8000L)
#define BN_MASK2h (0xffff0000L)
#define BN_CBIT ((unsigned long long)0x100000000LL)
#define BN_TBIT (0x80000000L)
#define BN_NOT_MASK2 ((unsigned long long)0xffffffff00000000LL)
#endif
#ifdef SIXTEEN_BIT
#define BN_ULLONG unsigned long
#define BN_ULONG unsigned short
#define BN_LONG short
#define BN_BITS 32
#define BN_BYTES 2
#define BN_BITS2 16
#define BN_BITS4 8
#define BN_MASK2 (0xffff)
#define BN_MASK2l (0xff)
#define BN_MASK2h1 (0xff80)
#define BN_MASK2h (0xff00)
#define BN_CBIT ((unsigned long)0x10000L)
#define BN_TBIT (0x8000)
#define BN_NOT_MASK2 ((unsigned long)0xffff0000L)
#endif
#define BN_DEFAULT_BITS 1200
#ifdef BIGNUM
#undef BIGNUM
#endif
typedef struct bignum_st
{
BN_ULONG *d; // Pointer to an array of 'BN_BITS2' bit chunks.
int top; // Index of last used d +1.
// The next are internal book keeping for bn_expand.
int max; // Size of the d array.
int neg;
} BIGNUM;
#define BN_CTX_NUM 12
typedef struct bignum_ctx
{
int tos;
BIGNUM *bn[BN_CTX_NUM];
} BN_CTX;
#define BN_prime_checks (5)
#define BN_num_bytes(a) ((BN_num_bits(a)+7)/8)
#define BN_is_zero(a) (((a)->top <= 1) && ((a)->d[0] == 0))
#define BN_is_one(a) (((a)->top == 1) && ((a)->d[0] == 1))
#define BN_is_word(a,w) (((a)->top == 1) && ((a)->d[0] == (w)))
#define BN_one(a) (BN_set_word((a),1))
#define BN_zero(a) (BN_set_word((a),0))
#define bn_fix_top(a) \
{ \
BN_ULONG *l; \
for (l= &((a)->d[(a)->top-1]); (a)->top > 0; (a)->top--) \
if (*(l--)) break; \
}
#define bn_expand(n,b) ((((b)/BN_BITS2) <= (n)->max)?(n):bn_expand2((n),(b)))
#define LBITS(a) ((a)&BN_MASK2l)
#define HBITS(a) (((a)>>BN_BITS4)&BN_MASK2l)
#define L2HBITS(a) (((a)&BN_MASK2l)<<BN_BITS4)
#define sqr64(lo,ho,in) \
{ \
BN_ULONG l,h,m; \
\
h=(in); \
l=LBITS(h); \
h=HBITS(h); \
m =(l)*(h); \
l*=l; \
h*=h; \
h+=(m&BN_MASK2h1)>>(BN_BITS4-1); \
m =(m&BN_MASK2l)<<(BN_BITS4+1); \
l+=m; if ((l&BN_MASK2) < m) h++; \
(lo)=l; \
(ho)=h; \
}
#define mul_add(r,a,bl,bh,c) { \
BN_ULONG l,h; \
\
h= (a); \
l=LBITS(h); \
h=HBITS(h); \
mul64(l,h,(bl),(bh)); \
\
/* non-multiply part */ \
l+=(c); if ((l&BN_MASK2) < (c)) h++; \
(c)=(r); \
l+=(c); if ((l&BN_MASK2) < (c)) h++; \
(c)=h&BN_MASK2; \
(r)=l&BN_MASK2; \
}
/*************************************************************/
// No long long type
#define mul64(l,h,bl,bh) \
{ \
BN_ULONG m,m1,lt,ht; \
\
lt=l; \
ht=h; \
m =(bh)*(lt); \
lt=(bl)*(lt); \
m1=(bl)*(ht); \
ht =(bh)*(ht); \
m+=m1; if ((m&BN_MASK2) < m1) ht+=L2HBITS(1L); \
ht+=HBITS(m); \
m1=L2HBITS(m); \
lt+=m1; if ((lt&BN_MASK2) < m1) ht++; \
(l)=lt; \
(h)=ht; \
}
#define mul(r,a,bl,bh,c) { \
BN_ULONG l,h; \
\
h= (a); \
l=LBITS(h); \
h=HBITS(h); \
mul64(l,h,(bl),(bh)); \
\
/* non-multiply part */ \
l+=(c); if ((l&BN_MASK2) < (c)) h++; \
(c)=h&BN_MASK2; \
r=l&BN_MASK2; \
if (--num == 0) break; \
}
#define bn_mul_words(r1,r2,a,b) \
{ \
BN_ULONG l,h,bl,bh; \
\
h=(a); \
l=LBITS(h); \
h=HBITS(h); \
bh=(b); \
bl=LBITS(bh); \
bh=HBITS(bh); \
\
mul64(l,h,bl,bh); \
\
(r1)=l; \
(r2)=h; \
}
static int BN_sub(BIGNUM *r, BIGNUM *a, BIGNUM *b);
static BN_ULONG bn_mul_add_word(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w);
static int BN_mod_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m, BN_CTX *ctx);
#define Getenv getenv
#define Fprintf fprintf
#define Fputc fputc
#define Fgets fgets
#define Fwrite fwrite
#define Fread fread
#ifdef sgi
#define IRIX_CC_BUG // all version of IRIX I've tested (4.* 5.*)
#endif
static BN_ULONG data_one=1L;
static BIGNUM const_one={&data_one,1,1,0};
BIGNUM *BN_value_one=&const_one;
int number_range( int from, int to );
/**************************************************************************/
static void RAND_bytes(unsigned char *buf,int num)
{
int i;
{
static unsigned char val;
for (i=0; i<num; i++){
val=number_range(1,250);
buf[i]=val++;
}
return;
}
}
/**************************************************************************/
static int BN_num_bits(BIGNUM *a)
{
int i;
BN_ULONG l;
static char bits[256]={
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
};
if(!a->top){
return 0;
}
l=a->d[a->top-1];
i=(a->top-1)*BN_BITS2;
if(l == 0){
return 0;
// bugf("BAD TOP VALUE\n");
// abort();
}
#ifdef SIXTY_FOUR_BIT
if(l & 0xffffffff00000000){
if(l & 0xffff000000000000){
if(l & 0xff00000000000000){
return(i+bits[l>>56]+56);
}else{
return(i+bits[l>>48]+48);
}
}else{
if(l & 0x0000ff0000000000){
return(i+bits[l>>40]+40);
}else{
return(i+bits[l>>32]+32);
}
}
}else
#endif
{
#if defined(THIRTY_TWO_BIT) || defined(SIXTY_FOUR_BIT)
if(l & 0xffff0000L){
if(l & 0xff000000L){
return (i+bits[l>>24L]+24);
}else{
return (i+bits[l>>16L]+16);
}
}else
#endif
{
if(l & 0xff00L){
return (i+bits[l>>8]+8);
}else{
return (i+bits[l]);
}
}
}
}
/**************************************************************************/
// ignores negative
static int BN_bn2bin(BIGNUM *a, unsigned char *to)
{
int n,i;
BN_ULONG l;
n=i=BN_num_bytes(a);
while (i-- > 0){
l=a->d[i/BN_BYTES];
*(to++)=(unsigned char)(l>>(8*(i%BN_BYTES)))&0xff;
}
return(n);
}
/**************************************************************************/
static void BN_free(BIGNUM *a)
{
if(!a){
return;
}
if(a->d){
free(a->d);
}
free(a);
}
/**************************************************************************/
static BIGNUM *BN_new()
{
BIGNUM *ret;
BN_ULONG *p;
ret=(BIGNUM *)malloc(sizeof(BIGNUM));
if(ret == NULL){
return NULL;
}
ret->top=0;
ret->neg=0;
ret->max=(BN_DEFAULT_BITS/BN_BITS2);
p=(BN_ULONG *)malloc(sizeof(BN_ULONG)*(ret->max+1));
if(p == NULL){
return NULL;
}
ret->d=p;
memset(p,0,(ret->max+1)*sizeof(p[0]));
return(ret);
}
/**************************************************************************/
static void BN_clear(BIGNUM *a)
{
memset(a->d,0,a->max*sizeof(a->d[0]));
a->top=0;
a->neg=0;
}
/**************************************************************************/
static void BN_clear_free(BIGNUM *a)
{
if(!a){
return;
}
if(a->d){
memset(a->d,0,a->max*sizeof(a->d[0]));
free(a->d);
}
memset(a,0,sizeof(BIGNUM));
free(a);
}
/**************************************************************************/
static void BN_CTX_free(BN_CTX *c)
{
int i;
for (i=0; i<BN_CTX_NUM; i++){
BN_clear_free(c->bn[i]);
}
free(c);
}
/**************************************************************************/
static BN_CTX *BN_CTX_new()
{
BN_CTX *ret;
BIGNUM *n;
int i, j;
ret=(BN_CTX *)malloc(sizeof(BN_CTX));
if(!ret){
return NULL;
}
for (i=0; i<BN_CTX_NUM; i++){
n=BN_new();
if(!n){
for (j=0; j<i; j++)
BN_free(ret->bn[j]);
free(ret);
return NULL;
}
ret->bn[i]=n;
}
ret->tos=0;
return ret;
}
/**************************************************************************/
static BIGNUM *bn_expand2(BIGNUM *b, int bits)
{
BN_ULONG *p;
register int n;
while (bits > b->max*BN_BITS2){
n=((bits+BN_BITS2-1)/BN_BITS2)*2;
p=b->d=(BN_ULONG *)realloc(b->d,sizeof(BN_ULONG)*(n+1));
if(!p){
return NULL;
}
memset(&(p[b->max]),0,((n+1)-b->max)*sizeof(BN_ULONG));
b->max=n;
}
return b;
}
/**************************************************************************/
// ignores negative
static BIGNUM *BN_bin2bn(unsigned char *s, int len, BIGNUM *ret)
{
unsigned int i,m;
unsigned int n;
BN_ULONG l;
if(!ret){
ret=BN_new();
}
if(!ret){
return NULL;
}
l=0;
n=len;
if(n==0){
ret->top=0;
return ret;
}
if(bn_expand(ret,(int)(n+2)*8) == NULL){
return NULL;
}
i=((n-1)/BN_BYTES)+1;
m=((n-1)%(BN_BYTES));
ret->top=i;
while (n-- > 0){
l=(l<<8)| *(s++);
if(m-- == 0){
ret->d[--i]=l;
l=0;
m=BN_BYTES-1;
}
}
// need to call this due to clear byte at top if avoiding
// having the top bit set (-ve number)
bn_fix_top(ret); // macro
return(ret);
}
/**************************************************************************/
static int BN_set_word(BIGNUM *a,unsigned long w)
{
if(bn_expand(a,(int)sizeof(unsigned long)*8) == NULL){
return 0;
}
a->d[0]=w;
a->top=(w == 0)?0:1;
a->neg=0;
return 1;
}
/**************************************************************************/
static BIGNUM *BN_copy(BIGNUM *a, BIGNUM *b)
{
if(bn_expand(a,b->top*BN_BITS2) == NULL){
return NULL;
}
memcpy(a->d,b->d,sizeof(b->d[0])*b->top);
memset(&(a->d[b->top]),0,sizeof(a->d[0])*(a->max-b->top));
a->top=b->top;
a->neg=b->neg;
return(a);
}
/**************************************************************************/
static int BN_is_bit_set(BIGNUM *a, int n)
{
int i,j;
i=n/BN_BITS2;
j=n%BN_BITS2;
if(a->top <= i){
return 0;
}
return ((a->d[i]&(1L<<j))?1:0);
}
/**************************************************************************/
static int BN_rshift(BIGNUM *r, BIGNUM *a, int n)
{
int i,nw,lb,rb;
BN_ULONG *t,*f;
BN_ULONG l;
r->neg=a->neg;
nw=n/BN_BITS2;
rb=n%BN_BITS2;
lb=BN_BITS2-rb;
if(nw > a->top){
BN_zero(r);
return 1;
}
if(bn_expand(r,(a->top-nw+1)*BN_BITS2) == NULL){
return 0;
}
f=a->d;
t=r->d;
if(rb == 0){
for (i=nw; i<a->top; i++){
t[i-nw]=f[i];
}
}else{
l=f[nw];
for (i=nw; i<a->top; i++){
t[i-nw] =(l>>rb)&BN_MASK2;
l=f[i+1];
t[i-nw]|=(l<<lb)&BN_MASK2;
}
}
r->top=a->top-nw;
t[r->top]=0;
bn_fix_top(r);
return 1;
}
/**************************************************************************/
static int BN_lshift(BIGNUM *r, BIGNUM *a, int n)
{
int i,nw,lb,rb;
BN_ULONG *t,*f;
BN_ULONG l;
r->neg=a->neg;
if(bn_expand(r,(a->top*BN_BITS2)+n) == NULL) return(0);
nw=n/BN_BITS2;
lb=n%BN_BITS2;
rb=BN_BITS2-lb;
f=a->d;
t=r->d;
t[a->top+nw]=0;
if(lb == 0)
for (i=a->top-1; i>=0; i--)
t[nw+i]=f[i];
else
for (i=a->top-1; i>=0; i--)
{
l=f[i];
t[nw+i+1]|=(l>>rb)&BN_MASK2;
t[nw+i]=(l<<lb)&BN_MASK2;
}
memset(t,0,nw*sizeof(t[0]));
r->top=a->top+nw+1;
bn_fix_top(r);
return(1);
}
/**************************************************************************/
static int BN_ucmp(BIGNUM *a, BIGNUM *b)
{
int i;
BN_ULONG t1,t2,*ap,*bp;
i=a->top-b->top;
if(i != 0) return(i);
ap=a->d;
bp=b->d;
for(i=a->top-1; i>=0; i--){
t1=ap[i];
t2=bp[i];
if(t1 > t2) return(1);
if(t1 < t2) return(-1);
}
return 0;
}
/**************************************************************************/
static int BN_cmp(BIGNUM *a, BIGNUM *b)
{
int i;
int gt,lt;
BN_ULONG t1,t2;
if(a->neg != b->neg){
if(a->neg){
return(-1);
}else{ return(1);}
}
if(a->neg == 0){
gt=1; lt=-1;
}else{
gt=-1; lt=1;
}
if(a->top > b->top) return(gt);
if(a->top < b->top) return(lt);
for (i=a->top-1; i>=0; i--){
t1=a->d[i];
t2=b->d[i];
if(t1 > t2) return(gt);
if(t1 < t2) return(lt);
}
return(0);
}
/**************************************************************************/
static void bn_SUB(BIGNUM *r, BIGNUM *a, BIGNUM *b)
{
int max,min;
register BN_ULONG t1,t2,*ap,*bp,*rp;
int i,carry;
#if defined(IRIX_CC_BUG) && !defined(LINT)
int dummy;
#endif
max=a->top;
min=b->top;
ap=a->d;
bp=b->d;
rp=r->d;
carry=0;
for (i=0; i<min; i++){
t1= *(ap++);
t2= *(bp++);
if(carry){
carry=(t1 <= t2);
t1=(t1-t2-1);
}else{
carry=(t1 < t2);
t1=(t1-t2);
}
#if defined(IRIX_CC_BUG) && !defined(LINT)
dummy=t1;
#endif
*(rp++)=t1&BN_MASK2;
}
if(carry){ // subtracted
while (i < max){
i++;
t1= *(ap++);
t2=(t1-1)&BN_MASK2;
*(rp++)=t2;
if(t1 > t2) break;
}
}
memcpy(rp,ap,sizeof(*rp)*(max-i));
r->top=max;
bn_fix_top(r);
}
/**************************************************************************/
static int BN_add(BIGNUM *r, BIGNUM *a, BIGNUM *b)
{
register int i;
int max,min;
BN_ULONG *ap,*bp,*rp,carry,t1,t2;
BIGNUM *tmp;
// a + b a+b
// a + -b a-b
// -a + b b-a
// -a + -b -(a+b)
if(a->neg ^ b->neg){
if(a->neg){
a->neg=0; i=BN_sub(r,b,a); if(a != r) a->neg=1;
}else{
b->neg=0; i=BN_sub(r,a,b); if(b != r) b->neg=1;
}
return(i);
}
if(a->neg){ // both are neg
a->neg=0; b->neg=0; i=BN_add(r,a,b);
if(a != r) a->neg=1;
if(b != r) b->neg=1;
return(i);
}
if(a->top < b->top){
tmp=a; a=b; b=tmp;
}
max=a->top;
min=b->top;
if(bn_expand(r,(max+1)*BN_BITS2) == NULL) return(0);
r->top=max;
r->neg=0;
ap=a->d;
bp=b->d;
rp=r->d;
carry=0;
for(i=0; i<min; i++){
t1= *(ap++);
t2= *(bp++);
if(carry){
carry=(t2 >= ((~t1)&BN_MASK2));
t2=(t1+t2+1)&BN_MASK2;
}else{
t2=(t1+t2)&BN_MASK2;
carry=(t2 < t1);
}
*(rp++)=t2;
}
if(carry){
while (i < max){
t1= *(ap++);
t2=(t1+1)&BN_MASK2;
*(rp++)=t2;
carry=(t2 < t1);
i++;
if(!carry) break;
}
if((i >= max) && carry){
*(rp++)=1;
r->top++;
}
}
for (; i<max; i++){
*(rp++)= *(ap++);
}
memcpy(rp,ap,sizeof(*ap)*(max-i));
return(1);
}
/**************************************************************************/
static int BN_sub(BIGNUM *r, BIGNUM *a, BIGNUM *b)
{
int max,i;
/* a - b a-b
* a - -b a+b
* -a - b -(a+b)
* -a - -b b-a
*/
if(a->neg){
if(b->neg){
a->neg=b->neg=0;
i=BN_sub(r,b,a);
if(a != r) a->neg=1;
if(b != r) b->neg=1;
}else{
a->neg=0;
i=BN_add(r,a,b);
r->neg=a->neg=1;
}
return(i);
}else{
if(b->neg){
b->neg=0;
i=BN_add(r,a,b);
if(r != b) b->neg=1;
return(i);
}
}
max=(a->top > b->top)?a->top:b->top;
if(BN_cmp(a,b) < 0){
if(bn_expand(r,max*BN_BITS2) == NULL) return(0);
bn_SUB(r,b,a);
r->neg=1;
}else{
if(bn_expand(r,max*BN_BITS2) == NULL) return(0);
bn_SUB(r,a,b);
r->neg=0;
}
return(1);
}
/**************************************************************************/
static int BN_rshift1(BIGNUM *r, BIGNUM *a)
{
BN_ULONG *ap,*rp,t,c;
int i;
if(BN_is_zero(a)){
BN_zero(r);
return(1);
}
if(a!=r){
if(bn_expand(r,a->top*BN_BITS2) == NULL){
return 0;
}
r->top=a->top;
r->neg=a->neg;
}
ap=a->d;
rp=r->d;
c=0;
for (i=a->top-1; i>=0; i--){
t=ap[i];
rp[i]=((t>>1)&BN_MASK2)|c;
c=(t&1)?BN_TBIT:0;
}
bn_fix_top(r);
return 1;
}
/**************************************************************************/
static int BN_mod(BIGNUM *rem, BIGNUM *m, BIGNUM *d, BN_CTX *ctx)
{
int i,nm,nd;
BIGNUM *dv;
if(BN_ucmp(m,d) < 0){
return((BN_copy(rem,m) == NULL)?0:1);
}
dv=ctx->bn[ctx->tos];
if(!BN_copy(rem,m)) {
return 0;
}
nm=BN_num_bits(rem);
nd=BN_num_bits(d);
if(!BN_lshift(dv,d,nm-nd)){
return 0;
}
for(i=nm-nd; i>=0; i--)
{
if(BN_cmp(rem,dv) >= 0){
if(!BN_sub(rem,rem,dv)){
return 0;
}
}
if(!BN_rshift1(dv,dv)){
return 0;
}
}
return 1;
}
/**************************************************************************/
static int BN_lshift1(BIGNUM *r, BIGNUM *a)
{
register BN_ULONG *ap,*rp,t,c;
int i;
if (r != a){
r->neg=a->neg;
if (bn_expand(r,(a->top+1)*BN_BITS2) == NULL) return(0);
r->top=a->top;
}else{
if (bn_expand(r,(a->top+1)*BN_BITS2) == NULL) return(0);
}
ap=a->d;
rp=r->d;
c=0;
for (i=0; i<a->top; i++){
t= *(ap++);
*(rp++)=((t<<1)|c)&BN_MASK2;
c=(t & BN_TBIT)?1:0;
}
if(c){
*rp=1;
r->top++;
}
return(1);
}
/**************************************************************************/
static int BN_div(BIGNUM *dv, BIGNUM *rem, BIGNUM *m, BIGNUM *d, BN_CTX *ctx)
{
int i,nm,nd;
BIGNUM *D;
if(BN_cmp(m,d) < 0){
if(rem != NULL){
if(BN_copy(rem,m) == NULL){
return(0);
}
}
if(dv != NULL){
BN_zero(dv);
}
return(1);
}
D=ctx->bn[ctx->tos];
if(dv == NULL) dv=ctx->bn[ctx->tos+1];
if(rem == NULL) rem=ctx->bn[ctx->tos+2];
nd=BN_num_bits(d);
nm=BN_num_bits(m);
if(BN_copy(D,d) == NULL) return(0);
if(BN_copy(rem,m) == NULL) return(0);
// The next 2 are needed so we can do a dv->d[0]|=1 later
// since BN_lshift1 will only work once there is a value :-)
BN_zero(dv);
dv->top=1;
if(!BN_lshift(D,D,nm-nd)){
return(0);
}
for (i=nm-nd; i>=0; i--){
if(!BN_lshift1(dv,dv)) return(0);
if(BN_cmp(rem,D) >= 0){
dv->d[0]|=1;
if(!BN_sub(rem,rem,D)){
return(0);
}
}
if(!BN_rshift1(D,D)) return(0);
}
dv->neg=m->neg^d->neg;
return(1);
}
/**************************************************************************/
static int BN_reciprocal(BIGNUM *r, BIGNUM *m, BN_CTX *ctx)
{
int nm,ret=-1;
BIGNUM *t;
t=ctx->bn[ctx->tos++];
nm=BN_num_bits(m);
if(!BN_lshift(t,BN_value_one,nm*2)) goto err;
if(!BN_div(r,NULL,t,m,ctx)) goto err;
ret=(nm+1);
err:
ctx->tos--;
return(ret);
}
/**************************************************************************/
static void bn_sqr_words(BN_ULONG *r, BN_ULONG *a, int n)
{
for (;;){
sqr64(r[0],r[1],a[0]);
if (--n == 0) break;
sqr64(r[2],r[3],a[1]);
if (--n == 0) break;
sqr64(r[4],r[5],a[2]);
if (--n == 0) break;
sqr64(r[6],r[7],a[3]);
if (--n == 0) break;
a+=4;
r+=8;
}
}
/**************************************************************************/
// r must not be a
static int BN_sqr(BIGNUM *r, BIGNUM *a, BN_CTX *ctx)
{
int i,j,max,al;
BIGNUM *tmp;
BN_ULONG *ap,*rp;
tmp=ctx->bn[ctx->tos];
al=a->top;
if (al == 0){
r->top=0;
return(1);
}
max=(al*2+1);
BN_clear(r);
BN_clear(tmp);
if (bn_expand(r,(max+1)*BN_BITS2) == NULL) return(0);
if (bn_expand(tmp,(max+1)*BN_BITS2) == NULL) return(0);
r->top=max;
r->neg=a->neg;
ap=a->d;
rp=r->d;
rp++;
j=al;
for (i=1; i<al; i++){
BN_ULONG r;
j--;
r= *(ap++);
rp[j]+=bn_mul_add_word(rp,ap,j,r);
rp+=2;
}
bn_fix_top(r);
if (!BN_lshift1(r,r)) return(0);
bn_sqr_words(tmp->d,a->d,a->top);
tmp->top=al*2+1;
bn_fix_top(tmp);
if (!BN_add(r,r,tmp)) return(0);
return(1);
}
/**************************************************************************/
// r must be different to a and b
static int BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b)
{
int i;
int max,al,bl;
BN_ULONG *ap,*bp,*rp;
al=a->top;
bl=b->top;
if ((al == 0) || (bl == 0)){
r->top=0;
return(1);
}
max=(al+bl+1);
BN_clear(r);
if (bn_expand(r,(max+1)*BN_BITS2) == NULL) return(0);
r->top=max;
r->neg=a->neg^b->neg;
ap=a->d;
bp=b->d;
rp=r->d;
for (i=0; i<bl; i++){
rp[al]=bn_mul_add_word(rp,ap,al,*(bp++));
rp++;
}
bn_fix_top(r);
return(1);
}
/**************************************************************************/
static BN_ULONG bn_mul_add_word(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
{
BN_ULONG c=0;
BN_ULONG bl,bh;
bl=LBITS(w);
bh=HBITS(w);
for (;;){
mul_add(rp[0],ap[0],bl,bh,c);
if (--num == 0) break;
mul_add(rp[1],ap[1],bl,bh,c);
if (--num == 0) break;
mul_add(rp[2],ap[2],bl,bh,c);
if (--num == 0) break;
mul_add(rp[3],ap[3],bl,bh,c);
if (--num == 0) break;
ap+=4;
rp+=4;
}
return(c);
}
/**************************************************************************/
static int mg_crypt_text(int flen, unsigned char *from, unsigned char *to,
BIGNUM *e, BIGNUM *n)
{
BIGNUM *f=NULL,*ret=NULL;
int i,j,k,num=0,r=-1;
unsigned char *p;
unsigned char *buf=NULL;
BN_CTX *ctx;
ctx=BN_CTX_new();
if(!ctx){
goto err;
}
num=BN_num_bytes(n); // macro
if(flen > (num-11)){
goto err;
}
buf=(unsigned char *)malloc(num);
if(!buf){
goto err;
}
p=(unsigned char *)buf;
*(p++)=0;
*(p++)=2;
// pad out with non-zero random data
j=num-3-flen;
RAND_bytes(p,j);
for(i=0; i<j; i++){
if (*p == '\0'){
do{
RAND_bytes(p,1);
} while (*p == '\0');
}
p++;
}
*(p++)='\0';
memcpy(p,from,(unsigned int)flen);
f=BN_new();
ret=BN_new();
if( !f || !ret ){
goto err;
}
if(BN_bin2bn(buf,num,f) == NULL) goto err;
if(!BN_mod_exp(ret,f,e,n,ctx)) goto err;
// put in leading 0 bytes if the number is less than the
// length of the modulus
j=BN_num_bytes(ret);
i=BN_bn2bin(ret,&(to[num-j]));
for (k=0; k<(num-i); k++)
to[k]=0;
r=num;
err:
if (ctx != NULL) BN_CTX_free(ctx);
if (f != NULL) BN_free(f);
if (ret != NULL) BN_free(ret);
if (buf != NULL)
{
memset(buf,0,num);
free(buf);
}
return(r);
}
/**************************************************************************/
int mg_crypt_msg(char *input, char *encoded)
{
int len;
BIGNUM *e=BN_bin2bn((unsigned char *)eh, eKEYSIZE, NULL);
BIGNUM *n=BN_bin2bn((unsigned char *)nh, nKEYSIZE, NULL);
len=mg_crypt_text(str_len(input), (unsigned char *)input,
(unsigned char *)encoded, e, n);
BN_free(e);
BN_free(n);
return len;
}
/**************************************************************************/
static int BN_mod_mul_reciprocal(BIGNUM *r, BIGNUM *x, BIGNUM *y, BIGNUM *m,
BIGNUM *i, int nb, BN_CTX *ctx)
{
int ret=0,j;
BIGNUM *a,*b,*c,*d;
a=ctx->bn[ctx->tos++];
b=ctx->bn[ctx->tos++];
c=ctx->bn[ctx->tos++];
d=ctx->bn[ctx->tos++];
if(x==y){
if(!BN_sqr(a,x,ctx)){
goto err;
}
}else{
if(!BN_mul(a,x,y)){
goto err;
}
}
if(!BN_rshift(d,a,nb-1)) goto err;
if(!BN_mul(b,d,i)) goto err;
if(!BN_rshift(c,b,nb-1)) goto err;
if(!BN_mul(b,m,c)) goto err;
if(!BN_sub(r,a,b)) goto err;
j=0;
while (BN_cmp(r,m) >= 0){
if(j++ > 2){
goto err;
}
if(!BN_sub(r,r,m)){
goto err;
}
}
ret=1;
err:
ctx->tos-=4;
return(ret);
}
/**************************************************************************/
static int BN_mod_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m, BN_CTX *ctx)
{
int nb,i,j=0,bits,ret=0;
BIGNUM *v,*tmp,*d,*pc[8];
BN_CTX *c2=NULL;
v=ctx->bn[ctx->tos];
tmp=ctx->bn[ctx->tos+1];
d=ctx->bn[ctx->tos+2];
ctx->tos+=3;
if(!BN_mod(v,a,m,ctx)){
goto err;
}
bits=BN_num_bits(p);
if(!BN_one(r)){
goto err;
}
nb=BN_reciprocal(d,m,ctx);
if(nb == -1){
goto err;
}
if((c2=BN_CTX_new()) == NULL){
goto err;
}
for (i=0; i<8; i++){
pc[i]=c2->bn[i];
}
c2->tos+=7;
if(!BN_copy(pc[1],v)) goto err;
if(!BN_mod_mul_reciprocal(pc[2],pc[1],pc[1],m,d,nb,ctx)) goto err;
if(!BN_mod_mul_reciprocal(pc[3],pc[2],pc[1],m,d,nb,ctx)) goto err;
if(!BN_mod_mul_reciprocal(pc[4],pc[2],pc[2],m,d,nb,ctx)) goto err;
if(!BN_mod_mul_reciprocal(pc[5],pc[4],pc[1],m,d,nb,ctx)) goto err;
if(!BN_mod_mul_reciprocal(pc[6],pc[3],pc[3],m,d,nb,ctx)) goto err;
if(!BN_mod_mul_reciprocal(pc[7],pc[6],pc[1],m,d,nb,ctx)) goto err;
bits=((bits-1)/3)*3; // for 4 bits, start at 2
for (i=bits; i>=0; i-=3){
if(!BN_mod_mul_reciprocal(r,r,r,m,d,nb,ctx)) goto err;
if(!BN_mod_mul_reciprocal(r,r,r,m,d,nb,ctx)) goto err;
if(!BN_mod_mul_reciprocal(r,r,r,m,d,nb,ctx)) goto err;
j= BN_is_bit_set(p,i)+
(BN_is_bit_set(p,i+1)<<1)+
(BN_is_bit_set(p,i+2)<<2);
if(j && !BN_mod_mul_reciprocal(r,r,pc[j],m,d,nb,ctx)){
goto err;
}
#ifdef BN_FIXED_TIME
else{
if(!BN_mod_mul_reciprocal(pc[0],r,pc[5],m,d,nb,ctx)){
goto err;
}
}
#endif
}
ret=1;
err:
if(c2){
BN_CTX_free(c2);
}
ctx->tos-=3;
return(ret);
}
/**************************************************************************/