encrypt(3)

πŸ’– encrypt(3) πŸ’–

ok so like. bestie. this is a page from the Library Functions Manual, and it's about the encrypt(3) family of functions. sit down, grab a strawberry πŸ“, because this one is a little cursed and I need you to know that going in.


✨ NAME ✨

encrypt, setkey, encrypt_r, setkey_r β€” encrypt 64-bit messages

no cap, that's literally the whole name section. four functions, one job: scrambling sixty-four bits. πŸ’…


πŸ“š LIBRARY πŸ“š

Password hashing library β€” that's libcrypt, and you link it with -lcrypt.


🩷 SYNOPSIS 🩷

okay so first up, the non-reentrant girlies. these need _XOPEN_SOURCE:

#define _XOPEN_SOURCE       /* See feature_test_macros(7) */
#include <unistd.h>

[[deprecated]] void encrypt(char block[64], int edflag);

#define _XOPEN_SOURCE       /* See feature_test_macros(7) */
#include <stdlib.h>

[[deprecated]] void setkey(const char *key);

and then the reentrant versions, who are special and need _GNU_SOURCE instead:

#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <crypt.h>

[[deprecated]] void setkey_r(const char *key, struct crypt_data *data);
[[deprecated]] void encrypt_r(char *block, int edflag,
                              struct crypt_data *data);

notice how every single one of them is tagged [[deprecated]]? yeah. that's not a vibe, that's a warning. πŸ™ˆ


🌸 DESCRIPTION 🌸

So these functions encrypt and decrypt 64-bit messages. iconic concept, honestly.

setkey() is the one that sets up the key that encrypt() is gonna use. the key argument here is an array of 64 bytes, and every single byte has a numerical value of either 1 or 0 β€” it's not "a password string", bestie, it's a bit vector. 🧚

and here's the little detail everyone forgets: the bytes key[n] where n=8*i-1 are ignored, so the effective key length is 56 bits. not 64. fifty-six. the universe takes its little tax. ✨

encrypt() modifies the buffer you handed it β€” it encodes if edflag is 0, and decodes if 1 is being passed. and just like the key argument, block is also a bit vector representation of the actual value that's being encoded. the result comes back in that same vector. no new allocation, no return value, it just mutates your array. main character behavior honestly. πŸ‘‘

Now. the tea. β˜• setkey() and encrypt() are not reentrant β€” meaning the key data is kept in static storage. static storage is giving "shared dorm fridge" energy. everyone's touching it, nobody's cleaning it, and if two threads walk in at once it's chaos. 😭

so that's why setkey_r() and encrypt_r() exist β€” they're the reentrant versions. they use this structure to hold the key data:

struct crypt_data {
    char keysched[16 * 8];
    char sb0[32768];
    char sb1[32768];
    char sb2[32768];
    char sb3[32768];
    char crypt_3_buf[14];
    char current_salt[2];
    long current_saltbits;
    int  direction;
    int  initialized;
};

look at those sb arrays. 32768 each. four of them. that struct is thicc and it is not sorry. 🫢

⚠️ IMPORTANT: before calling setkey_r(), set data->initialized to zero. do not skip this. this is not optional. this is the whole ritual. πŸ’€

πŸ’œ RETURN VALUE πŸ’œ

These functions do not return any value.

they're void. they give you nothing back. they simply do. it's giving mysterious. it's giving "I changed your buffer and left". πŸ¦‹


πŸŽ€ ERRORS πŸŽ€

Set errno to zero before calling the above functions. on success, errno is unchanged. so like, set it to zero, call the thing, check if it moved. that's the whole dance. πŸ’ƒ

  • ENOSYS β€” The function is not provided. (for example because of former USA export restrictions.) yes really. cryptography used to be regulated like weapons. that's the lore. 😭

πŸ’… ATTRIBUTES πŸ’…

for an explanation of the terms used in this section, see attributes(7). (they had a whole table here, we're doing bullets because tables are not the vibe in a terminal, but every cell is here, promise 🀞)

  • encrypt(), setkey() β€” Thread safety: MT-Unsafe race:crypt β€” yeah. race condition. the static storage thing. told you. 🚩
  • encrypt_r(), setkey_r() β€” Thread safety: MT-Safe β€” slay. the _r girlies ate. ✨

🌈 STANDARDS 🌈

  • encrypt(), setkey() β€” POSIX.1-2008.
  • encrypt_r(), setkey_r() β€” None.

so the reentrant versions aren't standardized by anyone. they're just glibc doing its own thing. free spirits. πŸ¦‹


πŸ•°οΈ HISTORY πŸ•°οΈ

Removed in glibc 2.28. 😭

and the reason is real: because they employ the DES block cipher, which is no longer considered secure, these functions were removed from glibc. applications should switch to a modern cryptography library, such as libgcrypt.

like. DES is not it anymore. DES is a locked diary with a hairpin. please, for the love of everything, move to something modern. πŸ™

  • encrypt(), setkey() β€” POSIX.1-2001, SUS, SVr4. (they've been around forever. they've seen things.)

Availability in glibc

See crypt(3).

Features in glibc

In glibc 2.2, these functions use the DES algorithm.


πŸ₯š EXAMPLES πŸ₯š

okay this example is genuinely cute β€” it encrypts and decrypts the word "eggplant". yes, eggplant. πŸ† iconic. here it is, exactly:

#define _XOPEN_SOURCE
#include <crypt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main(void)
{
    char key[64];
    char orig[9] = "eggplant";
    char buf[64];
    char txt[9];

    for (size_t i = 0; i < 64; i++) {
        key[i] = rand() & 1;
    }

    for (size_t i = 0; i < 8; i++) {
        for (size_t j = 0; j < 8; j++) {
            buf[i * 8 + j] = orig[i] >> j & 1;
        }
        setkey(key);
    }
    printf("Before encrypting: %s\n", orig);

    encrypt(buf, 0);
    for (size_t i = 0; i < 8; i++) {
        for (size_t j = 0, txt[i] = '\0'; j < 8; j++) {
            txt[i] |= buf[i * 8 + j] << j;
        }
        txt[8] = '\0';
    }
    printf("After encrypting:  %s\n", txt);

    encrypt(buf, 1);
    for (size_t i = 0; i < 8; i++) {
        for (size_t j = 0, txt[i] = '\0'; j < 8; j++) {
            txt[i] |= buf[i * 8 + j] << j;
        }
        txt[8] = '\0';
    }
    printf("After decrypting:  %s\n", txt);
    exit(EXIT_SUCCESS);
}

see how much manual bit-shuffling that is? every character explodes into 8 bits, gets encrypted, gets reassembled. that's the DES life. it's a lot of work for "eggplant". πŸ’€


πŸ‘€ SEE ALSO πŸ‘€


real talk bestie: these are [[deprecated]] in the synopsis, they were removed in glibc 2.28, and they run DES, which is cooked. if you're writing new code, go find a modern cryptography library. this page is history, not a plan. πŸ’–

and that's the whole page!! this came out of the Linux man-pages, release 6.20, dated 2026-02-08, and it's the encrypt(3) page. love that for us. mwah. πŸ’…βœ¨πŸŽ€

πŸ“¦ where this page comes from
  • arch rolling: man-pages 6.20-1 Β· BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • πŸ“œ the page's license: GPL-2.0-or-later
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms