bigcrypt.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * This function implements the "bigcrypt" algorithm specifically for
  3. * Linux-PAM.
  4. *
  5. * This algorithm is algorithm 0 (default) shipped with the C2 secure
  6. * implementation of Digital UNIX.
  7. *
  8. * Disclaimer: This work is not based on the source code to Digital
  9. * UNIX, nor am I connected to Digital Equipment Corp, in any way
  10. * other than as a customer. This code is based on published
  11. * interfaces and reasonable guesswork.
  12. *
  13. * Description: The cleartext is divided into blocks of SEGMENT_SIZE=8
  14. * characters or less. Each block is encrypted using the standard UNIX
  15. * libc crypt function. The result of the encryption for one block
  16. * provides the salt for the succeeding block.
  17. *
  18. * Restrictions: The buffer used to hold the encrypted result is
  19. * statically allocated. (see MAX_PASS_LEN below). This is necessary,
  20. * as the returned pointer points to "static data that are overwritten
  21. * by each call", (XPG3: XSI System Interface + Headers pg 109), and
  22. * this is a drop in replacement for crypt();
  23. *
  24. * Andy Phillips <atp@mssl.ucl.ac.uk>
  25. */
  26. #include "config.h"
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <security/_pam_macros.h>
  30. #ifdef HAVE_CRYPT_H
  31. #include <crypt.h>
  32. #endif
  33. #include "bigcrypt.h"
  34. /*
  35. * Max cleartext password length in segments of 8 characters this
  36. * function can deal with (16 segments of 8 chars= max 128 character
  37. * password).
  38. */
  39. #define MAX_PASS_LEN 16
  40. #define SEGMENT_SIZE 8
  41. #define SALT_SIZE 2
  42. #define KEYBUF_SIZE ((MAX_PASS_LEN*SEGMENT_SIZE)+SALT_SIZE)
  43. #define ESEGMENT_SIZE 11
  44. #define CBUF_SIZE ((MAX_PASS_LEN*ESEGMENT_SIZE)+SALT_SIZE+1)
  45. char *bigcrypt(const char *key, const char *salt)
  46. {
  47. char *dec_c2_cryptbuf;
  48. #ifdef HAVE_CRYPT_R
  49. struct crypt_data *cdata;
  50. #endif
  51. unsigned long int keylen, n_seg, j;
  52. char *cipher_ptr, *plaintext_ptr, *tmp_ptr, *salt_ptr;
  53. char keybuf[KEYBUF_SIZE + 1];
  54. D(("called with key='%s', salt='%s'.", key, salt));
  55. /* reset arrays */
  56. dec_c2_cryptbuf = malloc(CBUF_SIZE);
  57. if (!dec_c2_cryptbuf) {
  58. return NULL;
  59. }
  60. #ifdef HAVE_CRYPT_R
  61. cdata = malloc(sizeof(*cdata));
  62. if(!cdata) {
  63. free(dec_c2_cryptbuf);
  64. return NULL;
  65. }
  66. cdata->initialized = 0;
  67. #endif
  68. memset(keybuf, 0, KEYBUF_SIZE + 1);
  69. memset(dec_c2_cryptbuf, 0, CBUF_SIZE);
  70. /* fill KEYBUF_SIZE with key */
  71. strncpy(keybuf, key, KEYBUF_SIZE);
  72. /* deal with case that we are doing a password check for a
  73. conventially encrypted password: the salt will be
  74. SALT_SIZE+ESEGMENT_SIZE long. */
  75. if (strlen(salt) == (SALT_SIZE + ESEGMENT_SIZE))
  76. keybuf[SEGMENT_SIZE] = '\0'; /* terminate password early(?) */
  77. keylen = strlen(keybuf);
  78. if (!keylen) {
  79. n_seg = 1;
  80. } else {
  81. /* work out how many segments */
  82. n_seg = 1 + ((keylen - 1) / SEGMENT_SIZE);
  83. }
  84. if (n_seg > MAX_PASS_LEN)
  85. n_seg = MAX_PASS_LEN; /* truncate at max length */
  86. /* set up some pointers */
  87. cipher_ptr = dec_c2_cryptbuf;
  88. plaintext_ptr = keybuf;
  89. /* do the first block with supplied salt */
  90. #ifdef HAVE_CRYPT_R
  91. tmp_ptr = crypt_r(plaintext_ptr, salt, cdata); /* libc crypt_r() */
  92. #else
  93. tmp_ptr = crypt(plaintext_ptr, salt); /* libc crypt() */
  94. #endif
  95. if (tmp_ptr == NULL) {
  96. free(dec_c2_cryptbuf);
  97. #ifdef HAVE_CRYPT_R
  98. free(cdata);
  99. #endif
  100. return NULL;
  101. }
  102. /* and place in the static area */
  103. strncpy(cipher_ptr, tmp_ptr, 13);
  104. cipher_ptr += ESEGMENT_SIZE + SALT_SIZE;
  105. plaintext_ptr += SEGMENT_SIZE; /* first block of SEGMENT_SIZE */
  106. /* change the salt (1st 2 chars of previous block) - this was found
  107. by dowsing */
  108. salt_ptr = cipher_ptr - ESEGMENT_SIZE;
  109. /* so far this is identical to "return crypt(key, salt);", if
  110. there is more than one block encrypt them... */
  111. if (n_seg > 1) {
  112. for (j = 2; j <= n_seg; j++) {
  113. #ifdef HAVE_CRYPT_R
  114. tmp_ptr = crypt_r(plaintext_ptr, salt_ptr, cdata);
  115. #else
  116. tmp_ptr = crypt(plaintext_ptr, salt_ptr);
  117. #endif
  118. if (tmp_ptr == NULL) {
  119. _pam_overwrite(dec_c2_cryptbuf);
  120. free(dec_c2_cryptbuf);
  121. #ifdef HAVE_CRYPT_R
  122. free(cdata);
  123. #endif
  124. return NULL;
  125. }
  126. /* skip the salt for seg!=0 */
  127. strncpy(cipher_ptr, (tmp_ptr + SALT_SIZE), ESEGMENT_SIZE);
  128. cipher_ptr += ESEGMENT_SIZE;
  129. plaintext_ptr += SEGMENT_SIZE;
  130. salt_ptr = cipher_ptr - ESEGMENT_SIZE;
  131. }
  132. }
  133. D(("key=|%s|, salt=|%s|\nbuf=|%s|\n", key, salt, dec_c2_cryptbuf));
  134. #ifdef HAVE_CRYPT_R
  135. free(cdata);
  136. #endif
  137. /* this is the <NUL> terminated encrypted password */
  138. return dec_c2_cryptbuf;
  139. }