Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

653 lines
15 KiB
C

static char sccsid[] = "@(#)47 1.15 src/bos/usr/ccs/lib/libc/crypt.c, libcs, bos411, 9428A410j 11/22/93 11:26:22";
/*
* COMPONENT_NAME: (LIBCS) Standard C Library System Security Functions
*
* FUNCTIONS: crypt, _crypt, encrypt, _encrypt, setkey, _setkey
*
* ORIGINS: 3 26 27 71
*
* This module contains IBM CONFIDENTIAL code. -- (IBM
* Confidential Restricted when combined with the aggregated
* modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1985, 1993
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
/*
*
* Copyright (c) 1984 AT&T
* All Rights Reserved
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T
* The copyright notice above does not evidence any
* actual or intended publication of such source code.
*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
/*
*
*(c)Copyright 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC.
*ALL RIGHTS RESERVED
*/
#ifdef _DES_
#ifdef _THREAD_SAFE
#define _setkey_r __setkey_r
#define _crypt_r __crypt_r
#define _encrypt_r __encrypt_r
#else /* _THREAD_SAFE */
#define _setkey __setkey
#define _crypt __crypt
#define _encrypt __encrypt
#endif /* _THREAD_SAFE */
#endif /* _DES_ */
#ifdef _THREAD_SAFE
#include <crypt.h>
#define NULL 0
#endif /* _THREAD_SAFE */
#ifndef _DES_
#include <sys/errno.h>
#endif /* _DES_ */
/*
* This program implements a data encryption algorithm to _encrypt passwords.
*/
static int tr();
typedef char C16[16];
typedef char C24[24];
typedef char C28[28];
typedef char C32[32];
typedef char C48[48];
typedef char C64[64];
/* Moves n bytes from b to a, if a and b are well behaved */
/* Most compilers will be fooled into doing block moves */
#define Move(a,b,n) {struct foo {char x[n];}; \
*((struct foo *)a) = *((struct foo *)b); }
/* Xor's the n bytes at a with the n bytes at b */
#define Xor(a,b,n) { \
char *p=(char *)a, *q=(char *)b, *pe=(&((char *)a)[n]); \
while (p<pe) *p++ ^= *q++;}
/* Initial permutation, */
static C64 IP = {
57,49,41,33,25,17, 9, 1,
59,51,43,35,27,19,11, 3,
61,53,45,37,29,21,13, 5,
63,55,47,39,31,23,15, 7,
56,48,40,32,24,16, 8, 0,
58,50,42,34,26,18,10, 2,
60,52,44,36,28,20,12, 4,
62,54,46,38,30,22,14, 6};
/* * Final permutation, FP = IP^(-1) */
static C64 FP = {
39, 7,47,15,55,23,63,31,
38, 6,46,14,54,22,62,30,
37, 5,45,13,53,21,61,29,
36, 4,44,12,52,20,60,28,
35, 3,43,11,51,19,59,27,
34, 2,42,10,50,18,58,26,
33, 1,41, 9,49,17,57,25,
32, 0,40, 8,48,16,56,24};
/* Permuted-choice 1 from the key bits to yield C and D.
Note that bits 8,16... are left out: They are intended for a parity check. */
static C28 PC1_C = {
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};
static C28 PC1_D = {
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};
/* Sequence of shifts used for the key schedule. */
static C16 shifts = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
/* Permuted-choice 2, to pick out the bits from
the CD array that generate the key schedule. */
static C24 PC2_C = {
13,16,10,23, 0, 4,
2,27,14, 5,20, 9,
22,18,11, 3,25, 7,
15, 6,26,19,12, 1};
static C24 PC2_D = {
40,51,30,36,46,54,
29,39,50,44,32,47,
43,48,38,55,33,52,
45,41,49,35,28,31};
/* The E bit-selection table. */
static C48 E, e = {
31, 0, 1, 2, 3, 4,
3, 4, 5, 6, 7, 8,
7, 8, 9,10,11,12,
11,12,13,14,15,16,
15,16,17,18,19,20,
19,20,21,22,23,24,
23,24,25,26,27,28,
27,28,29,30,31, 0};
#ifndef _THREAD_SAFE
/* The key schedule. Generated from the key. */
static C48 KS[16];
#endif /* _THREAD_SAFE */
/*
* NAME: _setkey
*
* FUNCTION: Set a key into the crypt 'machine'.
*
* NOTES:
*/
/* Set up the key schedule from the key. */
#ifndef _DES_
static
#endif /* _DES_ */
#ifdef _THREAD_SAFE
int
_setkey_r(const char *key, CRYPTD *cd)
#else /* _THREAD_SAFE */
void
_setkey(const char *key)
#endif /* _THREAD_SAFE */
{
int i;
/* The C and D arrays used to calculate the key schedule. */
C28 C,D;
#ifdef _THREAD_SAFE
char *E;
char (*KS)[48];
if (cd == (CRYPTD *)NULL)
return -1;
E = cd->E;
KS = cd->KS;
#endif /* _THREAD_SAFE */
/* Generate C and D by permuting the key. The low order bit of each
8-bit char is not used, so C and D are only 28 bits apiece. */
Move(C,PC1_C,28); tr(C,key,28);
Move(D,PC1_D,28); tr(D,key,28);
/* To generate Ki, rotate C and D according
to schedule and pick up a permutation using PC2. */
for (i=0; i<16; i++) {
/* rotate. */
int k;
for (k=0; k<shifts[i]; k++) {
int j,t1,t2;
t1=C[0]; t2=D[0];
for (j=0; j<27; j++) {C[j]=C[j+1]; D[j]=D[j+1];}
C[27]=t1; D[27]=t2;}
/* get Ki. Note C and D are concatenated. */
for (k=0; k<24; k++) {
KS[i][k]=PC2_C[k];
KS[i][k+24]=PC2_D[k]-28;}
tr(KS[i],C,24); tr(&KS[i][24],D,24);}
Move(E,e,48);}
/* The 8 selection functions. For some reason, they give a 0-origin
index, unlike everything else. (Until Lee changed the others). */
static C64 S[8] = {{
14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7,
0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8,
4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0,
15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13},
{15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10,
3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5,
0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15,
13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9},
{10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1,
13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7,
1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12},
{7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15,
13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9,
10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4,
3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14},
{2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9,
14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6,
4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14,
11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3},
{12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11,
10,15, 4, 2, 7,12, 9, 5, 6, 1,13,14, 0,11, 3, 8,
9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6,
4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13},
{ 4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1,
13, 0,11, 7, 4, 9, 1,10,14, 3, 5,12, 2,15, 8, 6,
1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2,
6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12},
{13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7,
1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2,
7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8,
2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11}};
/* P is a permutation on the selected combination of the current L and key. */
static C32 P = {
15, 6,19,20, 28,11,27,16,
0,14,22,25, 4,17,30, 9,
1, 7,23,13, 31,26, 2, 8,
18,12,29, 5, 21,10, 3,24};
#define L work
#define R (&work[32])
/*
* NAME: _encrypt
*
* FUNCTION: Encrypt/decrypt a block.
*
* NOTES:
*/
#ifdef RETURN
#undef RETURN
#endif /* RETURN */
#ifdef _THREAD_SAFE
#define RETURN(__a) return(__a)
#else /* _THREAD_SAFE */
#define RETURN(_a) return
#endif /* _THREAD_SAFE */
/* The payoff: _encrypt a block. */
#ifndef _DES_
static
#endif /* _DES_ */
#ifdef _THREAD_SAFE
int
_encrypt_r(char block[64], int edflag, CRYPTD *cd)
#else /* _THREAD_SAFE */
void
_encrypt(char block[64], int edflag)
#endif /* _THREAD_SAFE */
{
int j,i,ii;
/* Work is current block, divided into 2 halves. */
/* PreS is combination of the key and the input, before selection. */
C64 work; C48 preS; C32 tempL,f;
#ifdef _THREAD_SAFE
char *E;
char (*KS)[48];
if (cd == (CRYPTD *)NULL)
RETURN(-1);
E = cd->E;
KS = cd->KS;
#endif /* _THREAD_SAFE */
#ifndef _DES_
/**********
** LIBC VERSION: if edflag is set (do decrypt) set errno and return
**********/
if (edflag) {
errno=ENOSYS;
RETURN(-1);
}
#endif /* _DES_ */
/* First, permute the bits in the input */
Move(work,IP,64); tr(work,block,64);
/* Perform an encryption operation 16 times. */
for (ii=0; ii<16; ii++) {
/* Set direction */
#ifdef _DES_
if (edflag)
i = 15-ii;
else
#endif /* _DES_ */
i = ii;
/* Save the R array, which will be the new L. */
Move(tempL,R,32);
/* Expand R to 48 bits using the E selector;
exclusive-or with the current key bits. */
Move(preS,E,48); tr(preS,R,48); Xor(preS,KS[i],48);
/* The pre-select bits are now considered in 8 groups of
* 6 bits each. The 8 selection functions map these
* 6-bit quantities into 4-bit quantities and the results
* permuted to make an f(R, K).
* The indexing into the selection functions is peculiar;
* it could be simplified by rewriting the tables. */
for (j=0; j<8; j++) {
char *p = &preS[6*j];
int k = 0;
if (*p++) k|=0x20;
if (*p++) k|=0x08;
if (*p++) k|=0x04;
if (*p++) k|=0x02;
if (*p++) k|=0x01;
if (*p) k|=0x10;
k = S[j][k];
p = &f[4*(j+1)];
*--p = (k&1)!=0;
*--p = (k&2)!=0;
*--p = (k&4)!=0;
*--p = (k&8)!=0;}
/* The new R is L ^ f(R, K).
The f here has to be permuted first, though. */
Move(R,P,32); tr(R,f,32); Xor(R,L,32);
/* Finally, the new L (the original R) is copied back. */
Move(L,tempL,32);}
/* The output L and R are reversed. */
{C32 t; Move(t,L,32); Move(L,R,32); Move(R,t,32);}
/* The final output gets the inverse permutation of the original. */
Move(block,FP,64); tr(block,work,64);
RETURN(0);
}
/*
* NAME: _crypt
*
* FUNCTION: Encrypt a password.
*
* NOTES:
*
* RETURN VALUE DESCRIPTION: the encrypted password
*/
#ifndef _DES_
static
#endif /* _DES_ */
#ifdef _THREAD_SAFE
char *
_crypt_r(const char *pw, const char *salt, CRYPTD *cd)
#else /* _THREAD_SAFE */
char *
_crypt(const char *pw, const char *salt)
#endif /* _THREAD_SAFE */
{
int i, j, c;
int temp;
#ifndef _THREAD_SAFE
static char block[66], iobuf[16];
#else /* _THREAD_SAFE */
char *E;
char *block;
char *iobuf;
if (cd == (CRYPTD *)NULL)
return(0);
E = cd->E;
block = cd->block;
iobuf = cd->iobuf;
#endif /* _THREAD_SAFE */
for(i=0; i < 66; i++)
block[i] = 0;
for(i=0; (c= *pw) && i < 64; pw++) {
for(j=0; j < 7; j++, i++)
block[i] = (c>>(6-j)) & 01;
i++;
}
#ifdef _THREAD_SAFE
_setkey_r(block, cd);
#else /* _THREAD_SAFE */
_setkey(block);
#endif /* _THREAD_SAFE */
for(i=0; i < 66; i++)
block[i] = 0;
for(i=0; i < 2; i++) {
c = *salt++;
iobuf[i] = c;
if(c > 'Z')
c -= 6;
if(c > '9')
c -= 7;
c -= '.';
for(j=0; j < 6; j++) {
if((c>>j) & 01) {
int k=6*i+j;
temp = E[k];
E[k] = E[k+24];
E[k+24] = temp;
}
}
}
for(i=0; i < 25; i++)
#ifdef _THREAD_SAFE
_encrypt_r(block,0,cd);
#else /* _THREAD_SAFE */
_encrypt(block,0);
#endif /* _THREAD_SAFE */
for(i=0; i < 11; i++) {
c = 0;
for(j=0; j < 6; j++) {
c <<= 1;
c |= block[6*i+j];
}
c += '.';
if(c > '9')
c += 7;
if(c > 'Z')
c += 6;
iobuf[i+2] = c;
}
iobuf[i+2] = 0;
if(iobuf[1] == 0)
iobuf[1] = iobuf[0];
return(iobuf);
}
static
tr(char *dst,char *tab,int cnt)
{
char *rdst=dst, *rtab=tab, *rend=rdst+cnt;
while (rdst<rend) {*rdst = rtab[*rdst]; rdst++;}
}
#ifndef _DES_
static void __load_crypt_functions(void);
static __setup=0;
#ifdef _THREAD_SAFE
extern char *__crypt_r();
extern int __encrypt_r();
extern int __setkey_r();
static char *(*crypt_function)() = _crypt_r;
static int (*setkey_function)() = _setkey_r;
static int (*encrypt_function)() = _encrypt_r;
extern struct rec_mutex _crypt_rmutex;
#else /* _THREAD_SAFE */
extern char *__crypt();
extern void __encrypt();
extern void __setkey();
static char *(*crypt_function)() = _crypt;
static void (*setkey_function)() = _setkey;
static void (*encrypt_function)() = _encrypt;
#endif /* _THREAD_SAFE */
/*
* NAME: crypt
*
* FUNCTION: If libdes is found, then load and run __crypt from libdes,
* otherwise run _crypt from libc.
*
* NOTES:
*/
#ifdef _THREAD_SAFE
char *
crypt_r(const char *pw, const char *salt, CRYPTD *cd)
#else /* _THREAD_SAFE */
char *
crypt(const char *pw, const char *salt)
#endif /* _THREAD_SAFE */
{
#ifdef _THREAD_SAFE
_rec_mutex_lock(&_crypt_rmutex);
#endif /* _THREAD_SAFE */
if (!__setup) {
__setup=1;
__load_crypt_functions();
}
#ifdef _THREAD_SAFE
_rec_mutex_unlock(&_crypt_rmutex);
return( (*crypt_function)(pw, salt,cd) );
#else /* _THREAD_SAFE */
return( (*crypt_function)(pw, salt) );
#endif /* _THREAD_SAFE */
}
/*
* NAME: setkey
*
* FUNCTION: If libdes is found, then load and run __setkey from libdes,
* otherwise run _setkey from libc.
*
* NOTES:
*/
#ifdef _THREAD_SAFE
int
setkey_r(const char *key, CRYPTD *cd)
#else /* _THREAD_SAFE */
void
setkey(const char *key)
#endif /* _THREAD_SAFE */
{
#ifdef _THREAD_SAFE
_rec_mutex_lock(&_crypt_rmutex);
#endif /* _THREAD_SAFE */
if (!__setup) {
__setup=1;
__load_crypt_functions();
}
#ifdef _THREAD_SAFE
_rec_mutex_unlock(&_crypt_rmutex);
(*setkey_function)(key, cd);
#else /* _THREAD_SAFE */
(*setkey_function)(key);
#endif /* _THREAD_SAFE */
}
/*
* NAME: encrypt
*
* FUNCTION: If libdes is found, then load and run __encrypt from libdes,
* otherwise run _encrypt from libc.
*
*
* NOTES:
*/
#ifdef _THREAD_SAFE
int
encrypt_r(char block[64], int edflag, CRYPTD *cd)
#else /* _THREAD_SAFE */
void
encrypt(char block[64], int edflag)
#endif /* _THREAD_SAFE */
{
#ifdef _THREAD_SAFE
_rec_mutex_lock(&_crypt_rmutex);
#endif /* _THREAD_SAFE */
if (!__setup) {
__setup=1;
__load_crypt_functions();
}
#ifdef _THREAD_SAFE
_rec_mutex_unlock(&_crypt_rmutex);
(*encrypt_function)(block, edflag, cd);
#else /* _THREAD_SAFE */
(*encrypt_function)(block, edflag);
#endif /* _THREAD_SAFE */
}
static
void
__load_crypt_functions()
{
int *load_rc;
int loadbind_rc;
/**********
try to load libdes, if this fails, then just use the ones
in libc
**********/
#ifdef _THREAD_SAFE
load_rc = load("libdes_r", 1 ,"/usr/lib");
#else /* _THREAD_SAFE */
load_rc = load("libdes", 1 ,"/usr/lib");
#endif /* _THREAD_SAFE */
if (load_rc == (int *) 0)
return;
/**********
Bind in any exported symbols from libdes, If this fails, unload
libdes and use the functions in libc
**********/
#ifdef _THREAD_SAFE
loadbind_rc = loadbind(0, _crypt_r, load_rc);
#else /* _THREAD_SAFE */
loadbind_rc = loadbind(0, _crypt, load_rc);
#endif /* _THREAD_SAFE */
if (loadbind_rc == -1) {
(void) unload(load_rc);
return;
}
/**********
libdes is loaded, set up the function pointers and return
**********/
#ifdef _THREAD_SAFE
crypt_function = __crypt_r;
setkey_function = __setkey_r;
encrypt_function = __encrypt_r;
#else /* _THREAD_SAFE */
crypt_function = __crypt;
setkey_function = __setkey;
encrypt_function = __encrypt;
#endif /* _THREAD_SAFE */
return;
}
#endif /* _DES_ */