*: slap on a few ALIGN1/2s where appropriate
[oweals/busybox.git] / libbb / pw_encrypt.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Utility routines.
4  *
5  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8  */
9
10 #include "libbb.h"
11
12 /* static const uint8_t ascii64[] ALIGN1 =
13  * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
14  */
15
16 static int i64c(int i)
17 {
18         i &= 0x3f;
19         if (i == 0)
20                 return '.';
21         if (i == 1)
22                 return '/';
23         if (i < 12)
24                 return ('0' - 2 + i);
25         if (i < 38)
26                 return ('A' - 12 + i);
27         return ('a' - 38 + i);
28 }
29
30 int FAST_FUNC crypt_make_salt(char *p, int cnt /*, int x */)
31 {
32         /* was: x += ... */
33         int x = getpid() + monotonic_us();
34         do {
35                 /* x = (x*1664525 + 1013904223) % 2^32 generator is lame
36                  * (low-order bit is not "random", etc...),
37                  * but for our purposes it is good enough */
38                 x = x*1664525 + 1013904223;
39                 /* BTW, Park and Miller's "minimal standard generator" is
40                  * x = x*16807 % ((2^31)-1)
41                  * It has no problem with visibly alternating lowest bit
42                  * but is also weak in cryptographic sense + needs div,
43                  * which needs more code (and slower) on many CPUs */
44                 *p++ = i64c(x >> 16);
45                 *p++ = i64c(x >> 22);
46         } while (--cnt);
47         *p = '\0';
48         return x;
49 }
50
51 char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo)
52 {
53         int len = 2/2;
54         char *salt_ptr = salt;
55
56         /* Standard chpasswd uses uppercase algos ("MD5", not "md5").
57          * Need to be case-insensitive in the code below.
58          */
59         if ((algo[0]|0x20) != 'd') { /* not des */
60                 len = 8/2; /* so far assuming md5 */
61                 *salt_ptr++ = '$';
62                 *salt_ptr++ = '1';
63                 *salt_ptr++ = '$';
64 #if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA
65                 if ((algo[0]|0x20) == 's') { /* sha */
66                         salt[1] = '5' + (strcasecmp(algo, "sha512") == 0);
67                         len = 16/2;
68                 }
69 #endif
70         }
71         crypt_make_salt(salt_ptr, len);
72         return salt_ptr;
73 }
74
75 #if ENABLE_USE_BB_CRYPT
76
77 static char*
78 to64(char *s, unsigned v, int n)
79 {
80         while (--n >= 0) {
81                 /* *s++ = ascii64[v & 0x3f]; */
82                 *s++ = i64c(v);
83                 v >>= 6;
84         }
85         return s;
86 }
87
88 /*
89  * DES and MD5 crypt implementations are taken from uclibc.
90  * They were modified to not use static buffers.
91  */
92
93 #include "pw_encrypt_des.c"
94 #include "pw_encrypt_md5.c"
95 #if ENABLE_USE_BB_CRYPT_SHA
96 #include "pw_encrypt_sha.c"
97 #endif
98
99 /* Other advanced crypt ids (TODO?): */
100 /* $2$ or $2a$: Blowfish */
101
102 static struct const_des_ctx *des_cctx;
103 static struct des_ctx *des_ctx;
104
105 /* my_crypt returns malloc'ed data */
106 static char *my_crypt(const char *key, const char *salt)
107 {
108         /* MD5 or SHA? */
109         if (salt[0] == '$' && salt[1] && salt[2] == '$') {
110                 if (salt[1] == '1')
111                         return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
112 #if ENABLE_USE_BB_CRYPT_SHA
113                 if (salt[1] == '5' || salt[1] == '6')
114                         return sha_crypt((char*)key, (char*)salt);
115 #endif
116         }
117
118         if (!des_cctx)
119                 des_cctx = const_des_init();
120         des_ctx = des_init(des_ctx, des_cctx);
121         return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
122 }
123
124 /* So far nobody wants to have it public */
125 static void my_crypt_cleanup(void)
126 {
127         free(des_cctx);
128         free(des_ctx);
129         des_cctx = NULL;
130         des_ctx = NULL;
131 }
132
133 char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
134 {
135         char *encrypted;
136
137         encrypted = my_crypt(clear, salt);
138
139         if (cleanup)
140                 my_crypt_cleanup();
141
142         return encrypted;
143 }
144
145 #else /* if !ENABLE_USE_BB_CRYPT */
146
147 char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
148 {
149         char *s;
150
151         s = crypt(clear, salt);
152         /*
153          * glibc used to return "" on malformed salts (for example, ""),
154          * but since 2.17 it returns NULL.
155          */
156         return xstrdup(s ? s : "");
157 }
158
159 #endif