1  /*
       2   * FreeSec: libcrypt for NetBSD
       3   *
       4   * Copyright (c) 1994 David Burren
       5   * All rights reserved.
       6   *
       7   * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet
       8   *	this file should now *only* export crypt(), in order to make
       9   *	binaries of libcrypt exportable from the USA
      10   *
      11   * Adapted for FreeBSD-4.0 by Mark R V Murray
      12   *	this file should now *only* export crypt_des(), in order to make
      13   *	a module that can be optionally included in libcrypt.
      14   *
      15   * Adapted for libxcrypt by Zack Weinberg, 2017
      16   *	see notes in des.c
      17   *
      18   * Adapted for libxcrypt by Björn Esser, 2019
      19   *	add function-stubs simply setting error to ENOSYS.
      20   *
      21   * Redistribution and use in source and binary forms, with or without
      22   * modification, are permitted provided that the following conditions
      23   * are met:
      24   * 1. Redistributions of source code must retain the above copyright
      25   *    notice, this list of conditions and the following disclaimer.
      26   * 2. Redistributions in binary form must reproduce the above copyright
      27   *    notice, this list of conditions and the following disclaimer in the
      28   *    documentation and/or other materials provided with the distribution.
      29   * 3. Neither the name of the author nor the names of other contributors
      30   *    may be used to endorse or promote products derived from this software
      31   *    without specific prior written permission.
      32   *
      33   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
      34   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      35   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      36   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      37   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      38   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      39   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      40   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      41   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      42   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      43   * SUCH DAMAGE.
      44   *
      45   * This is an original implementation of the DES and the crypt(3) interfaces
      46   * by David Burren <davidb@werj.com.au>.
      47   */
      48  
      49  /* Obsolete DES symmetric cipher API - not to be used in new code.  */
      50  
      51  #include "crypt-port.h"
      52  #include "crypt-obsolete.h"
      53  #include "alg-des.h"
      54  #include <errno.h>
      55  
      56  #if (INCLUDE_encrypt || INCLUDE_encrypt_r || INCLUDE_setkey || INCLUDE_setkey_r) && \
      57      !ENABLE_OBSOLETE_API_ENOSYS
      58  
      59  static_assert(sizeof (struct des_ctx) + alignof (struct des_ctx)
      60                <= CRYPT_DATA_INTERNAL_SIZE,
      61                "crypt_data.internal is too small for struct des_ctx");
      62  
      63  /* struct crypt_data is allocated by application code and contains
      64     only char-typed fields, so its 'internal' field may not be
      65     sufficiently aligned.  */
      66  static inline struct des_ctx *
      67  get_des_ctx (struct crypt_data *data)
      68  {
      69    uintptr_t internalp = (uintptr_t) data->internal;
      70    const uintptr_t align = alignof (struct des_ctx);
      71    internalp = (internalp + align - 1) & ~(align - 1);
      72    return (struct des_ctx *)internalp;
      73  }
      74  
      75  /* For reasons lost in the mists of time, these functions operate on
      76     64-*byte* arrays, each of which should be either 0 or 1 - only the
      77     low bit of each byte is examined.  The DES primitives, much more
      78     sensibly, operate on 8-byte/64-*bit* arrays.  */
      79  
      80  static void
      81  unpack_bits (char bytev[64], const unsigned char bitv[8])
      82  {
      83    unsigned char c;
      84    for (int i = 0; i < 8; i++)
      85      {
      86        c = bitv[i];
      87        for (int j = 0; j < 8; j++)
      88          bytev[i*8 + j] = (char)((c & (0x01 << (7 - j))) != 0);
      89      }
      90  }
      91  
      92  static void
      93  pack_bits (unsigned char bitv[8], const char bytev[64])
      94  {
      95    unsigned int c;
      96    for (int i = 0; i < 8; i++)
      97      {
      98        c = 0;
      99        for (int j = 0; j < 8; j++)
     100          {
     101            c <<= 1;
     102            c |= ((unsigned char)bytev[i*8 + j] & 0x01u);
     103          }
     104        bitv[i] = (unsigned char)c;
     105      }
     106  }
     107  #endif
     108  
     109  /* Initialize DATA with a DES key, KEY, represented as a byte vector.  */
     110  #if (INCLUDE_setkey_r || INCLUDE_setkey) && !ENABLE_OBSOLETE_API_ENOSYS
     111  static void
     112  do_setkey_r (const char *key, struct des_ctx *ctx)
     113  {
     114    memset (ctx, 0, sizeof (struct des_ctx));
     115    des_set_salt (ctx, 0);
     116  
     117    unsigned char bkey[8];
     118    pack_bits (bkey, key);
     119    des_set_key (ctx, bkey);
     120  }
     121  #endif
     122  
     123  #if INCLUDE_setkey_r
     124  void
     125  setkey_r (ARG_UNUSED (const char *key), ARG_UNUSED (struct crypt_data *data))
     126  {
     127  #if ENABLE_OBSOLETE_API_ENOSYS
     128    /* This function is not supported in this configuration.  */
     129    errno = ENOSYS;
     130  #else
     131    do_setkey_r (key, get_des_ctx (data));
     132  #endif
     133  }
     134  SYMVER_setkey_r;
     135  #endif
     136  
     137  /* Encrypt or decrypt one DES block, BLOCK, using the key schedule in
     138     DATA.  BLOCK is processed in place.  */
     139  #if (INCLUDE_encrypt_r || INCLUDE_encrypt) && !ENABLE_OBSOLETE_API_ENOSYS
     140  static void
     141  do_encrypt_r (char *block, int edflag, struct des_ctx *ctx)
     142  {
     143    unsigned char bin[8], bout[8];
     144    pack_bits (bin, block);
     145    des_crypt_block (ctx, bout, bin, 1, edflag != 0);
     146    unpack_bits (block, bout);
     147  }
     148  #endif
     149  
     150  #if INCLUDE_encrypt_r
     151  void
     152  encrypt_r (char *block, ARG_UNUSED (int edflag),
     153             ARG_UNUSED (struct crypt_data *data))
     154  {
     155  #if ENABLE_OBSOLETE_API_ENOSYS
     156    /* Make sure sensitive data is erased in case
     157       case get_random_bytes() fails.  */
     158    explicit_bzero(block, 64);
     159  
     160    /* Overwrite sensitive data with random data.  */
     161    get_random_bytes(block, 64);
     162  
     163    /* This function is not supported in this configuration.  */
     164    errno = ENOSYS;
     165  #else
     166    do_encrypt_r (block, edflag, get_des_ctx (data));
     167  #endif
     168  }
     169  SYMVER_encrypt_r;
     170  #endif
     171  
     172  /* Even-more-deprecated-than-the-above nonreentrant versions.
     173     These use a separate state object from the main library's
     174     nonreentrant crypt().  Unlike with crypt() vs crypt_r(),
     175     these do not get their own file because they're not compiled
     176     into the static library anyway.  */
     177  
     178  #if (INCLUDE_setkey || INCLUDE_encrypt) && !ENABLE_OBSOLETE_API_ENOSYS
     179  static struct des_ctx nr_encrypt_ctx;
     180  #endif
     181  
     182  #if INCLUDE_setkey
     183  void
     184  setkey (ARG_UNUSED (const char *key))
     185  {
     186  #if ENABLE_OBSOLETE_API_ENOSYS
     187    /* This function is not supported in this configuration.  */
     188    errno = ENOSYS;
     189  #else
     190    do_setkey_r (key, &nr_encrypt_ctx);
     191  #endif
     192  }
     193  SYMVER_setkey;
     194  #endif
     195  
     196  #if INCLUDE_encrypt
     197  void
     198  encrypt (char *block, ARG_UNUSED (int edflag))
     199  {
     200  #if ENABLE_OBSOLETE_API_ENOSYS
     201    /* Make sure sensitive data is erased in case
     202       case get_random_bytes() fails.  */
     203    explicit_bzero(block, 64);
     204  
     205    /* Overwrite sensitive data with random data.  */
     206    get_random_bytes(block, 64);
     207  
     208    /* This function is not supported in this configuration.  */
     209    errno = ENOSYS;
     210  #else
     211    do_encrypt_r (block, edflag, &nr_encrypt_ctx);
     212  #endif
     213  }
     214  SYMVER_encrypt;
     215  #endif