/*
 * contrib/pgcrypto/crypt-blowfish.c
 *
 * This code comes from John the Ripper password cracker, with reentrant
 * and crypt(3) interfaces added, but optimizations specific to password
 * cracking removed.
 *
 * Written by Solar Designer <solar at openwall.com> in 1998-2002 and
 * placed in the public domain.
 *
 * There's absolutely no warranty.
 *
 * It is my intent that you should be able to use this on your system,
 * as a part of a software package, or anywhere else to improve security,
 * ensure compatibility, or for any other purpose. I would appreciate
 * it if you give credit where it is due and keep your modifications in
 * the public domain as well, but I don't require that in order to let
 * you place this code and any modifications you make under a license
 * of your choice.
 *
 * This implementation is compatible with OpenBSD bcrypt.c (version 2a)
 * by Niels Provos <provos at citi.umich.edu>, and uses some of his
 * ideas.  The password hashing algorithm was designed by David Mazieres
 * <dm at lcs.mit.edu>.
 *
 * There's a paper on the algorithm that explains its design decisions:
 *
 *	http://www.usenix.org/events/usenix99/provos.html
 *
 * Some of the tricks in BF_ROUND might be inspired by Eric Young's
 * Blowfish library (I can't be sure if I would think of something if I
 * hadn't seen his code).
 */

#include "postgres.h"
#include "knl/knl_variable.h"

#include "px-crypt.h"

#ifdef __i386__
#define BF_ASM 0 /* 1 */
#define BF_SCALE 1
#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__)
#define BF_ASM 0
#define BF_SCALE 1
#else
#define BF_ASM 0
#define BF_SCALE 0
#endif

typedef unsigned int BF_word;
typedef signed int BF_word_signed;

/* Number of Blowfish rounds, this is also hardcoded into a few places */
#define BF_N 16

typedef BF_word BF_key[BF_N + 2];

typedef struct {
    BF_word S[4][0x100];
    BF_key P;
} BF_ctx;

/*
 * Magic IV for 64 Blowfish encryptions that we do at the end.
 * The string is "OrpheanBeholderScryDoubt" on big-endian.
 */
static BF_word BF_magic_w[6] = {0x4F727068, 0x65616E42, 0x65686F6C, 0x64657253, 0x63727944, 0x6F756274};

/*
 * P-box and S-box tables initialized with digits of Pi.
 */
static BF_ctx BF_init_state = {{{0xd1310ba6,
                                    0x98dfb5ac,
                                    0x2ffd72db,
                                    0xd01adfb7,
                                    0xb8e1afed,
                                    0x6a267e96,
                                    0xba7c9045,
                                    0xf12c7f99,
                                    0x24a19947,
                                    0xb3916cf7,
                                    0x0801f2e2,
                                    0x858efc16,
                                    0x636920d8,
                                    0x71574e69,
                                    0xa458fea3,
                                    0xf4933d7e,
                                    0x0d95748f,
                                    0x728eb658,
                                    0x718bcd58,
                                    0x82154aee,
                                    0x7b54a41d,
                                    0xc25a59b5,
                                    0x9c30d539,
                                    0x2af26013,
                                    0xc5d1b023,
                                    0x286085f0,
                                    0xca417918,
                                    0xb8db38ef,
                                    0x8e79dcb0,
                                    0x603a180e,
                                    0x6c9e0e8b,
                                    0xb01e8a3e,
                                    0xd71577c1,
                                    0xbd314b27,
                                    0x78af2fda,
                                    0x55605c60,
                                    0xe65525f3,
                                    0xaa55ab94,
                                    0x57489862,
                                    0x63e81440,
                                    0x55ca396a,
                                    0x2aab10b6,
                                    0xb4cc5c34,
                                    0x1141e8ce,
                                    0xa15486af,
                                    0x7c72e993,
                                    0xb3ee1411,
                                    0x636fbc2a,
                                    0x2ba9c55d,
                                    0x741831f6,
                                    0xce5c3e16,
                                    0x9b87931e,
                                    0xafd6ba33,
                                    0x6c24cf5c,
                                    0x7a325381,
                                    0x28958677,
                                    0x3b8f4898,
                                    0x6b4bb9af,
                                    0xc4bfe81b,
                                    0x66282193,
                                    0x61d809cc,
                                    0xfb21a991,
                                    0x487cac60,
                                    0x5dec8032,
                                    0xef845d5d,
                                    0xe98575b1,
                                    0xdc262302,
                                    0xeb651b88,
                                    0x23893e81,
                                    0xd396acc5,
                                    0x0f6d6ff3,
                                    0x83f44239,
                                    0x2e0b4482,
                                    0xa4842004,
                                    0x69c8f04a,
                                    0x9e1f9b5e,
                                    0x21c66842,
                                    0xf6e96c9a,
                                    0x670c9c61,
                                    0xabd388f0,
                                    0x6a51a0d2,
                                    0xd8542f68,
                                    0x960fa728,
                                    0xab5133a3,
                                    0x6eef0b6c,
                                    0x137a3be4,
                                    0xba3bf050,
                                    0x7efb2a98,
                                    0xa1f1651d,
                                    0x39af0176,
                                    0x66ca593e,
                                    0x82430e88,
                                    0x8cee8619,
                                    0x456f9fb4,
                                    0x7d84a5c3,
                                    0x3b8b5ebe,
                                    0xe06f75d8,
                                    0x85c12073,
                                    0x401a449f,
                                    0x56c16aa6,
                                    0x4ed3aa62,
                                    0x363f7706,
                                    0x1bfedf72,
                                    0x429b023d,
                                    0x37d0d724,
                                    0xd00a1248,
                                    0xdb0fead3,
                                    0x49f1c09b,
                                    0x075372c9,
                                    0x80991b7b,
                                    0x25d479d8,
                                    0xf6e8def7,
                                    0xe3fe501a,
                                    0xb6794c3b,
                                    0x976ce0bd,
                                    0x04c006ba,
                                    0xc1a94fb6,
                                    0x409f60c4,
                                    0x5e5c9ec2,
                                    0x196a2463,
                                    0x68fb6faf,
                                    0x3e6c53b5,
                                    0x1339b2eb,
                                    0x3b52ec6f,
                                    0x6dfc511f,
                                    0x9b30952c,
                                    0xcc814544,
                                    0xaf5ebd09,
                                    0xbee3d004,
                                    0xde334afd,
                                    0x660f2807,
                                    0x192e4bb3,
                                    0xc0cba857,
                                    0x45c8740f,
                                    0xd20b5f39,
                                    0xb9d3fbdb,
                                    0x5579c0bd,
                                    0x1a60320a,
                                    0xd6a100c6,
                                    0x402c7279,
                                    0x679f25fe,
                                    0xfb1fa3cc,
                                    0x8ea5e9f8,
                                    0xdb3222f8,
                                    0x3c7516df,
                                    0xfd616b15,
                                    0x2f501ec8,
                                    0xad0552ab,
                                    0x323db5fa,
                                    0xfd238760,
                                    0x53317b48,
                                    0x3e00df82,
                                    0x9e5c57bb,
                                    0xca6f8ca0,
                                    0x1a87562e,
                                    0xdf1769db,
                                    0xd542a8f6,
                                    0x287effc3,
                                    0xac6732c6,
                                    0x8c4f5573,
                                    0x695b27b0,
                                    0xbbca58c8,
                                    0xe1ffa35d,
                                    0xb8f011a0,
                                    0x10fa3d98,
                                    0xfd2183b8,
                                    0x4afcb56c,
                                    0x2dd1d35b,
                                    0x9a53e479,
                                    0xb6f84565,
                                    0xd28e49bc,
                                    0x4bfb9790,
                                    0xe1ddf2da,
                                    0xa4cb7e33,
                                    0x62fb1341,
                                    0xcee4c6e8,
                                    0xef20cada,
                                    0x36774c01,
                                    0xd07e9efe,
                                    0x2bf11fb4,
                                    0x95dbda4d,
                                    0xae909198,
                                    0xeaad8e71,
                                    0x6b93d5a0,
                                    0xd08ed1d0,
                                    0xafc725e0,
                                    0x8e3c5b2f,
                                    0x8e7594b7,
                                    0x8ff6e2fb,
                                    0xf2122b64,
                                    0x8888b812,
                                    0x900df01c,
                                    0x4fad5ea0,
                                    0x688fc31c,
                                    0xd1cff191,
                                    0xb3a8c1ad,
                                    0x2f2f2218,
                                    0xbe0e1777,
                                    0xea752dfe,
                                    0x8b021fa1,
                                    0xe5a0cc0f,
                                    0xb56f74e8,
                                    0x18acf3d6,
                                    0xce89e299,
                                    0xb4a84fe0,
                                    0xfd13e0b7,
                                    0x7cc43b81,
                                    0xd2ada8d9,
                                    0x165fa266,
                                    0x80957705,
                                    0x93cc7314,
                                    0x211a1477,
                                    0xe6ad2065,
                                    0x77b5fa86,
                                    0xc75442f5,
                                    0xfb9d35cf,
                                    0xebcdaf0c,
                                    0x7b3e89a0,
                                    0xd6411bd3,
                                    0xae1e7e49,
                                    0x00250e2d,
                                    0x2071b35e,
                                    0x226800bb,
                                    0x57b8e0af,
                                    0x2464369b,
                                    0xf009b91e,
                                    0x5563911d,
                                    0x59dfa6aa,
                                    0x78c14389,
                                    0xd95a537f,
                                    0x207d5ba2,
                                    0x02e5b9c5,
                                    0x83260376,
                                    0x6295cfa9,
                                    0x11c81968,
                                    0x4e734a41,
                                    0xb3472dca,
                                    0x7b14a94a,
                                    0x1b510052,
                                    0x9a532915,
                                    0xd60f573f,
                                    0xbc9bc6e4,
                                    0x2b60a476,
                                    0x81e67400,
                                    0x08ba6fb5,
                                    0x571be91f,
                                    0xf296ec6b,
                                    0x2a0dd915,
                                    0xb6636521,
                                    0xe7b9f9b6,
                                    0xff34052e,
                                    0xc5855664,
                                    0x53b02d5d,
                                    0xa99f8fa1,
                                    0x08ba4799,
                                    0x6e85076a},
                                   {0x4b7a70e9,
                                       0xb5b32944,
                                       0xdb75092e,
                                       0xc4192623,
                                       0xad6ea6b0,
                                       0x49a7df7d,
                                       0x9cee60b8,
                                       0x8fedb266,
                                       0xecaa8c71,
                                       0x699a17ff,
                                       0x5664526c,
                                       0xc2b19ee1,
                                       0x193602a5,
                                       0x75094c29,
                                       0xa0591340,
                                       0xe4183a3e,
                                       0x3f54989a,
                                       0x5b429d65,
                                       0x6b8fe4d6,
                                       0x99f73fd6,
                                       0xa1d29c07,
                                       0xefe830f5,
                                       0x4d2d38e6,
                                       0xf0255dc1,
                                       0x4cdd2086,
                                       0x8470eb26,
                                       0x6382e9c6,
                                       0x021ecc5e,
                                       0x09686b3f,
                                       0x3ebaefc9,
                                       0x3c971814,
                                       0x6b6a70a1,
                                       0x687f3584,
                                       0x52a0e286,
                                       0xb79c5305,
                                       0xaa500737,
                                       0x3e07841c,
                                       0x7fdeae5c,
                                       0x8e7d44ec,
                                       0x5716f2b8,
                                       0xb03ada37,
                                       0xf0500c0d,
                                       0xf01c1f04,
                                       0x0200b3ff,
                                       0xae0cf51a,
                                       0x3cb574b2,
                                       0x25837a58,
                                       0xdc0921bd,
                                       0xd19113f9,
                                       0x7ca92ff6,
                                       0x94324773,
                                       0x22f54701,
                                       0x3ae5e581,
                                       0x37c2dadc,
                                       0xc8b57634,
                                       0x9af3dda7,
                                       0xa9446146,
                                       0x0fd0030e,
                                       0xecc8c73e,
                                       0xa4751e41,
                                       0xe238cd99,
                                       0x3bea0e2f,
                                       0x3280bba1,
                                       0x183eb331,
                                       0x4e548b38,
                                       0x4f6db908,
                                       0x6f420d03,
                                       0xf60a04bf,
                                       0x2cb81290,
                                       0x24977c79,
                                       0x5679b072,
                                       0xbcaf89af,
                                       0xde9a771f,
                                       0xd9930810,
                                       0xb38bae12,
                                       0xdccf3f2e,
                                       0x5512721f,
                                       0x2e6b7124,
                                       0x501adde6,
                                       0x9f84cd87,
                                       0x7a584718,
                                       0x7408da17,
                                       0xbc9f9abc,
                                       0xe94b7d8c,
                                       0xec7aec3a,
                                       0xdb851dfa,
                                       0x63094366,
                                       0xc464c3d2,
                                       0xef1c1847,
                                       0x3215d908,
                                       0xdd433b37,
                                       0x24c2ba16,
                                       0x12a14d43,
                                       0x2a65c451,
                                       0x50940002,
                                       0x133ae4dd,
                                       0x71dff89e,
                                       0x10314e55,
                                       0x81ac77d6,
                                       0x5f11199b,
                                       0x043556f1,
                                       0xd7a3c76b,
                                       0x3c11183b,
                                       0x5924a509,
                                       0xf28fe6ed,
                                       0x97f1fbfa,
                                       0x9ebabf2c,
                                       0x1e153c6e,
                                       0x86e34570,
                                       0xeae96fb1,
                                       0x860e5e0a,
                                       0x5a3e2ab3,
                                       0x771fe71c,
                                       0x4e3d06fa,
                                       0x2965dcb9,
                                       0x99e71d0f,
                                       0x803e89d6,
                                       0x5266c825,
                                       0x2e4cc978,
                                       0x9c10b36a,
                                       0xc6150eba,
                                       0x94e2ea78,
                                       0xa5fc3c53,
                                       0x1e0a2df4,
                                       0xf2f74ea7,
                                       0x361d2b3d,
                                       0x1939260f,
                                       0x19c27960,
                                       0x5223a708,
                                       0xf71312b6,
                                       0xebadfe6e,
                                       0xeac31f66,
                                       0xe3bc4595,
                                       0xa67bc883,
                                       0xb17f37d1,
                                       0x018cff28,
                                       0xc332ddef,
                                       0xbe6c5aa5,
                                       0x65582185,
                                       0x68ab9802,
                                       0xeecea50f,
                                       0xdb2f953b,
                                       0x2aef7dad,
                                       0x5b6e2f84,
                                       0x1521b628,
                                       0x29076170,
                                       0xecdd4775,
                                       0x619f1510,
                                       0x13cca830,
                                       0xeb61bd96,
                                       0x0334fe1e,
                                       0xaa0363cf,
                                       0xb5735c90,
                                       0x4c70a239,
                                       0xd59e9e0b,
                                       0xcbaade14,
                                       0xeecc86bc,
                                       0x60622ca7,
                                       0x9cab5cab,
                                       0xb2f3846e,
                                       0x648b1eaf,
                                       0x19bdf0ca,
                                       0xa02369b9,
                                       0x655abb50,
                                       0x40685a32,
                                       0x3c2ab4b3,
                                       0x319ee9d5,
                                       0xc021b8f7,
                                       0x9b540b19,
                                       0x875fa099,
                                       0x95f7997e,
                                       0x623d7da8,
                                       0xf837889a,
                                       0x97e32d77,
                                       0x11ed935f,
                                       0x16681281,
                                       0x0e358829,
                                       0xc7e61fd6,
                                       0x96dedfa1,
                                       0x7858ba99,
                                       0x57f584a5,
                                       0x1b227263,
                                       0x9b83c3ff,
                                       0x1ac24696,
                                       0xcdb30aeb,
                                       0x532e3054,
                                       0x8fd948e4,
                                       0x6dbc3128,
                                       0x58ebf2ef,
                                       0x34c6ffea,
                                       0xfe28ed61,
                                       0xee7c3c73,
                                       0x5d4a14d9,
                                       0xe864b7e3,
                                       0x42105d14,
                                       0x203e13e0,
                                       0x45eee2b6,
                                       0xa3aaabea,
                                       0xdb6c4f15,
                                       0xfacb4fd0,
                                       0xc742f442,
                                       0xef6abbb5,
                                       0x654f3b1d,
                                       0x41cd2105,
                                       0xd81e799e,
                                       0x86854dc7,
                                       0xe44b476a,
                                       0x3d816250,
                                       0xcf62a1f2,
                                       0x5b8d2646,
                                       0xfc8883a0,
                                       0xc1c7b6a3,
                                       0x7f1524c3,
                                       0x69cb7492,
                                       0x47848a0b,
                                       0x5692b285,
                                       0x095bbf00,
                                       0xad19489d,
                                       0x1462b174,
                                       0x23820e00,
                                       0x58428d2a,
                                       0x0c55f5ea,
                                       0x1dadf43e,
                                       0x233f7061,
                                       0x3372f092,
                                       0x8d937e41,
                                       0xd65fecf1,
                                       0x6c223bdb,
                                       0x7cde3759,
                                       0xcbee7460,
                                       0x4085f2a7,
                                       0xce77326e,
                                       0xa6078084,
                                       0x19f8509e,
                                       0xe8efd855,
                                       0x61d99735,
                                       0xa969a7aa,
                                       0xc50c06c2,
                                       0x5a04abfc,
                                       0x800bcadc,
                                       0x9e447a2e,
                                       0xc3453484,
                                       0xfdd56705,
                                       0x0e1e9ec9,
                                       0xdb73dbd3,
                                       0x105588cd,
                                       0x675fda79,
                                       0xe3674340,
                                       0xc5c43465,
                                       0x713e38d8,
                                       0x3d28f89e,
                                       0xf16dff20,
                                       0x153e21e7,
                                       0x8fb03d4a,
                                       0xe6e39f2b,
                                       0xdb83adf7},
                                   {0xe93d5a68,
                                       0x948140f7,
                                       0xf64c261c,
                                       0x94692934,
                                       0x411520f7,
                                       0x7602d4f7,
                                       0xbcf46b2e,
                                       0xd4a20068,
                                       0xd4082471,
                                       0x3320f46a,
                                       0x43b7d4b7,
                                       0x500061af,
                                       0x1e39f62e,
                                       0x97244546,
                                       0x14214f74,
                                       0xbf8b8840,
                                       0x4d95fc1d,
                                       0x96b591af,
                                       0x70f4ddd3,
                                       0x66a02f45,
                                       0xbfbc09ec,
                                       0x03bd9785,
                                       0x7fac6dd0,
                                       0x31cb8504,
                                       0x96eb27b3,
                                       0x55fd3941,
                                       0xda2547e6,
                                       0xabca0a9a,
                                       0x28507825,
                                       0x530429f4,
                                       0x0a2c86da,
                                       0xe9b66dfb,
                                       0x68dc1462,
                                       0xd7486900,
                                       0x680ec0a4,
                                       0x27a18dee,
                                       0x4f3ffea2,
                                       0xe887ad8c,
                                       0xb58ce006,
                                       0x7af4d6b6,
                                       0xaace1e7c,
                                       0xd3375fec,
                                       0xce78a399,
                                       0x406b2a42,
                                       0x20fe9e35,
                                       0xd9f385b9,
                                       0xee39d7ab,
                                       0x3b124e8b,
                                       0x1dc9faf7,
                                       0x4b6d1856,
                                       0x26a36631,
                                       0xeae397b2,
                                       0x3a6efa74,
                                       0xdd5b4332,
                                       0x6841e7f7,
                                       0xca7820fb,
                                       0xfb0af54e,
                                       0xd8feb397,
                                       0x454056ac,
                                       0xba489527,
                                       0x55533a3a,
                                       0x20838d87,
                                       0xfe6ba9b7,
                                       0xd096954b,
                                       0x55a867bc,
                                       0xa1159a58,
                                       0xcca92963,
                                       0x99e1db33,
                                       0xa62a4a56,
                                       0x3f3125f9,
                                       0x5ef47e1c,
                                       0x9029317c,
                                       0xfdf8e802,
                                       0x04272f70,
                                       0x80bb155c,
                                       0x05282ce3,
                                       0x95c11548,
                                       0xe4c66d22,
                                       0x48c1133f,
                                       0xc70f86dc,
                                       0x07f9c9ee,
                                       0x41041f0f,
                                       0x404779a4,
                                       0x5d886e17,
                                       0x325f51eb,
                                       0xd59bc0d1,
                                       0xf2bcc18f,
                                       0x41113564,
                                       0x257b7834,
                                       0x602a9c60,
                                       0xdff8e8a3,
                                       0x1f636c1b,
                                       0x0e12b4c2,
                                       0x02e1329e,
                                       0xaf664fd1,
                                       0xcad18115,
                                       0x6b2395e0,
                                       0x333e92e1,
                                       0x3b240b62,
                                       0xeebeb922,
                                       0x85b2a20e,
                                       0xe6ba0d99,
                                       0xde720c8c,
                                       0x2da2f728,
                                       0xd0127845,
                                       0x95b794fd,
                                       0x647d0862,
                                       0xe7ccf5f0,
                                       0x5449a36f,
                                       0x877d48fa,
                                       0xc39dfd27,
                                       0xf33e8d1e,
                                       0x0a476341,
                                       0x992eff74,
                                       0x3a6f6eab,
                                       0xf4f8fd37,
                                       0xa812dc60,
                                       0xa1ebddf8,
                                       0x991be14c,
                                       0xdb6e6b0d,
                                       0xc67b5510,
                                       0x6d672c37,
                                       0x2765d43b,
                                       0xdcd0e804,
                                       0xf1290dc7,
                                       0xcc00ffa3,
                                       0xb5390f92,
                                       0x690fed0b,
                                       0x667b9ffb,
                                       0xcedb7d9c,
                                       0xa091cf0b,
                                       0xd9155ea3,
                                       0xbb132f88,
                                       0x515bad24,
                                       0x7b9479bf,
                                       0x763bd6eb,
                                       0x37392eb3,
                                       0xcc115979,
                                       0x8026e297,
                                       0xf42e312d,
                                       0x6842ada7,
                                       0xc66a2b3b,
                                       0x12754ccc,
                                       0x782ef11c,
                                       0x6a124237,
                                       0xb79251e7,
                                       0x06a1bbe6,
                                       0x4bfb6350,
                                       0x1a6b1018,
                                       0x11caedfa,
                                       0x3d25bdd8,
                                       0xe2e1c3c9,
                                       0x44421659,
                                       0x0a121386,
                                       0xd90cec6e,
                                       0xd5abea2a,
                                       0x64af674e,
                                       0xda86a85f,
                                       0xbebfe988,
                                       0x64e4c3fe,
                                       0x9dbc8057,
                                       0xf0f7c086,
                                       0x60787bf8,
                                       0x6003604d,
                                       0xd1fd8346,
                                       0xf6381fb0,
                                       0x7745ae04,
                                       0xd736fccc,
                                       0x83426b33,
                                       0xf01eab71,
                                       0xb0804187,
                                       0x3c005e5f,
                                       0x77a057be,
                                       0xbde8ae24,
                                       0x55464299,
                                       0xbf582e61,
                                       0x4e58f48f,
                                       0xf2ddfda2,
                                       0xf474ef38,
                                       0x8789bdc2,
                                       0x5366f9c3,
                                       0xc8b38e74,
                                       0xb475f255,
                                       0x46fcd9b9,
                                       0x7aeb2661,
                                       0x8b1ddf84,
                                       0x846a0e79,
                                       0x915f95e2,
                                       0x466e598e,
                                       0x20b45770,
                                       0x8cd55591,
                                       0xc902de4c,
                                       0xb90bace1,
                                       0xbb8205d0,
                                       0x11a86248,
                                       0x7574a99e,
                                       0xb77f19b6,
                                       0xe0a9dc09,
                                       0x662d09a1,
                                       0xc4324633,
                                       0xe85a1f02,
                                       0x09f0be8c,
                                       0x4a99a025,
                                       0x1d6efe10,
                                       0x1ab93d1d,
                                       0x0ba5a4df,
                                       0xa186f20f,
                                       0x2868f169,
                                       0xdcb7da83,
                                       0x573906fe,
                                       0xa1e2ce9b,
                                       0x4fcd7f52,
                                       0x50115e01,
                                       0xa70683fa,
                                       0xa002b5c4,
                                       0x0de6d027,
                                       0x9af88c27,
                                       0x773f8641,
                                       0xc3604c06,
                                       0x61a806b5,
                                       0xf0177a28,
                                       0xc0f586e0,
                                       0x006058aa,
                                       0x30dc7d62,
                                       0x11e69ed7,
                                       0x2338ea63,
                                       0x53c2dd94,
                                       0xc2c21634,
                                       0xbbcbee56,
                                       0x90bcb6de,
                                       0xebfc7da1,
                                       0xce591d76,
                                       0x6f05e409,
                                       0x4b7c0188,
                                       0x39720a3d,
                                       0x7c927c24,
                                       0x86e3725f,
                                       0x724d9db9,
                                       0x1ac15bb4,
                                       0xd39eb8fc,
                                       0xed545578,
                                       0x08fca5b5,
                                       0xd83d7cd3,
                                       0x4dad0fc4,
                                       0x1e50ef5e,
                                       0xb161e6f8,
                                       0xa28514d9,
                                       0x6c51133c,
                                       0x6fd5c7e7,
                                       0x56e14ec4,
                                       0x362abfce,
                                       0xddc6c837,
                                       0xd79a3234,
                                       0x92638212,
                                       0x670efa8e,
                                       0x406000e0},
                                   {0x3a39ce37,
                                       0xd3faf5cf,
                                       0xabc27737,
                                       0x5ac52d1b,
                                       0x5cb0679e,
                                       0x4fa33742,
                                       0xd3822740,
                                       0x99bc9bbe,
                                       0xd5118e9d,
                                       0xbf0f7315,
                                       0xd62d1c7e,
                                       0xc700c47b,
                                       0xb78c1b6b,
                                       0x21a19045,
                                       0xb26eb1be,
                                       0x6a366eb4,
                                       0x5748ab2f,
                                       0xbc946e79,
                                       0xc6a376d2,
                                       0x6549c2c8,
                                       0x530ff8ee,
                                       0x468dde7d,
                                       0xd5730a1d,
                                       0x4cd04dc6,
                                       0x2939bbdb,
                                       0xa9ba4650,
                                       0xac9526e8,
                                       0xbe5ee304,
                                       0xa1fad5f0,
                                       0x6a2d519a,
                                       0x63ef8ce2,
                                       0x9a86ee22,
                                       0xc089c2b8,
                                       0x43242ef6,
                                       0xa51e03aa,
                                       0x9cf2d0a4,
                                       0x83c061ba,
                                       0x9be96a4d,
                                       0x8fe51550,
                                       0xba645bd6,
                                       0x2826a2f9,
                                       0xa73a3ae1,
                                       0x4ba99586,
                                       0xef5562e9,
                                       0xc72fefd3,
                                       0xf752f7da,
                                       0x3f046f69,
                                       0x77fa0a59,
                                       0x80e4a915,
                                       0x87b08601,
                                       0x9b09e6ad,
                                       0x3b3ee593,
                                       0xe990fd5a,
                                       0x9e34d797,
                                       0x2cf0b7d9,
                                       0x022b8b51,
                                       0x96d5ac3a,
                                       0x017da67d,
                                       0xd1cf3ed6,
                                       0x7c7d2d28,
                                       0x1f9f25cf,
                                       0xadf2b89b,
                                       0x5ad6b472,
                                       0x5a88f54c,
                                       0xe029ac71,
                                       0xe019a5e6,
                                       0x47b0acfd,
                                       0xed93fa9b,
                                       0xe8d3c48d,
                                       0x283b57cc,
                                       0xf8d56629,
                                       0x79132e28,
                                       0x785f0191,
                                       0xed756055,
                                       0xf7960e44,
                                       0xe3d35e8c,
                                       0x15056dd4,
                                       0x88f46dba,
                                       0x03a16125,
                                       0x0564f0bd,
                                       0xc3eb9e15,
                                       0x3c9057a2,
                                       0x97271aec,
                                       0xa93a072a,
                                       0x1b3f6d9b,
                                       0x1e6321f5,
                                       0xf59c66fb,
                                       0x26dcf319,
                                       0x7533d928,
                                       0xb155fdf5,
                                       0x03563482,
                                       0x8aba3cbb,
                                       0x28517711,
                                       0xc20ad9f8,
                                       0xabcc5167,
                                       0xccad925f,
                                       0x4de81751,
                                       0x3830dc8e,
                                       0x379d5862,
                                       0x9320f991,
                                       0xea7a90c2,
                                       0xfb3e7bce,
                                       0x5121ce64,
                                       0x774fbe32,
                                       0xa8b6e37e,
                                       0xc3293d46,
                                       0x48de5369,
                                       0x6413e680,
                                       0xa2ae0810,
                                       0xdd6db224,
                                       0x69852dfd,
                                       0x09072166,
                                       0xb39a460a,
                                       0x6445c0dd,
                                       0x586cdecf,
                                       0x1c20c8ae,
                                       0x5bbef7dd,
                                       0x1b588d40,
                                       0xccd2017f,
                                       0x6bb4e3bb,
                                       0xdda26a7e,
                                       0x3a59ff45,
                                       0x3e350a44,
                                       0xbcb4cdd5,
                                       0x72eacea8,
                                       0xfa6484bb,
                                       0x8d6612ae,
                                       0xbf3c6f47,
                                       0xd29be463,
                                       0x542f5d9e,
                                       0xaec2771b,
                                       0xf64e6370,
                                       0x740e0d8d,
                                       0xe75b1357,
                                       0xf8721671,
                                       0xaf537d5d,
                                       0x4040cb08,
                                       0x4eb4e2cc,
                                       0x34d2466a,
                                       0x0115af84,
                                       0xe1b00428,
                                       0x95983a1d,
                                       0x06b89fb4,
                                       0xce6ea048,
                                       0x6f3f3b82,
                                       0x3520ab82,
                                       0x011a1d4b,
                                       0x277227f8,
                                       0x611560b1,
                                       0xe7933fdc,
                                       0xbb3a792b,
                                       0x344525bd,
                                       0xa08839e1,
                                       0x51ce794b,
                                       0x2f32c9b7,
                                       0xa01fbac9,
                                       0xe01cc87e,
                                       0xbcc7d1f6,
                                       0xcf0111c3,
                                       0xa1e8aac7,
                                       0x1a908749,
                                       0xd44fbd9a,
                                       0xd0dadecb,
                                       0xd50ada38,
                                       0x0339c32a,
                                       0xc6913667,
                                       0x8df9317c,
                                       0xe0b12b4f,
                                       0xf79e59b7,
                                       0x43f5bb3a,
                                       0xf2d519ff,
                                       0x27d9459c,
                                       0xbf97222c,
                                       0x15e6fc2a,
                                       0x0f91fc71,
                                       0x9b941525,
                                       0xfae59361,
                                       0xceb69ceb,
                                       0xc2a86459,
                                       0x12baa8d1,
                                       0xb6c1075e,
                                       0xe3056a0c,
                                       0x10d25065,
                                       0xcb03a442,
                                       0xe0ec6e0e,
                                       0x1698db3b,
                                       0x4c98a0be,
                                       0x3278e964,
                                       0x9f1f9532,
                                       0xe0d392df,
                                       0xd3a0342b,
                                       0x8971f21e,
                                       0x1b0a7441,
                                       0x4ba3348c,
                                       0xc5be7120,
                                       0xc37632d8,
                                       0xdf359f8d,
                                       0x9b992f2e,
                                       0xe60b6f47,
                                       0x0fe3f11d,
                                       0xe54cda54,
                                       0x1edad891,
                                       0xce6279cf,
                                       0xcd3e7e6f,
                                       0x1618b166,
                                       0xfd2c1d05,
                                       0x848fd2c5,
                                       0xf6fb2299,
                                       0xf523f357,
                                       0xa6327623,
                                       0x93a83531,
                                       0x56cccd02,
                                       0xacf08162,
                                       0x5a75ebb5,
                                       0x6e163697,
                                       0x88d273cc,
                                       0xde966292,
                                       0x81b949d0,
                                       0x4c50901b,
                                       0x71c65614,
                                       0xe6c6c7bd,
                                       0x327a140a,
                                       0x45e1d006,
                                       0xc3f27b9a,
                                       0xc9aa53fd,
                                       0x62a80f00,
                                       0xbb25bfe2,
                                       0x35bdd2f6,
                                       0x71126905,
                                       0xb2040222,
                                       0xb6cbcf7c,
                                       0xcd769c2b,
                                       0x53113ec0,
                                       0x1640e3d3,
                                       0x38abbd60,
                                       0x2547adf0,
                                       0xba38209c,
                                       0xf746ce76,
                                       0x77afa1c5,
                                       0x20756060,
                                       0x85cbfe4e,
                                       0x8ae88dd8,
                                       0x7aaaf9b0,
                                       0x4cf9aa7e,
                                       0x1948c25c,
                                       0x02fb8a8c,
                                       0x01c36ae4,
                                       0xd6ebe1f9,
                                       0x90d4f869,
                                       0xa65cdea0,
                                       0x3f09252d,
                                       0xc208e69f,
                                       0xb74e6132,
                                       0xce77e25b,
                                       0x578fdfe3,
                                       0x3ac372e6}},
    {0x243f6a88,
        0x85a308d3,
        0x13198a2e,
        0x03707344,
        0xa4093822,
        0x299f31d0,
        0x082efa98,
        0xec4e6c89,
        0x452821e6,
        0x38d01377,
        0xbe5466cf,
        0x34e90c6c,
        0xc0ac29b7,
        0xc97c50dd,
        0x3f84d5b5,
        0xb5470917,
        0x9216d5d9,
        0x8979fb1b}};

static unsigned char BF_itoa64[64 + 1] = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

static unsigned char BF_atoi64[0x60] = {64,
    64,
    64,
    64,
    64,
    64,
    64,
    64,
    64,
    64,
    64,
    64,
    64,
    64,
    0,
    1,
    54,
    55,
    56,
    57,
    58,
    59,
    60,
    61,
    62,
    63,
    64,
    64,
    64,
    64,
    64,
    64,
    64,
    2,
    3,
    4,
    5,
    6,
    7,
    8,
    9,
    10,
    11,
    12,
    13,
    14,
    15,
    16,
    17,
    18,
    19,
    20,
    21,
    22,
    23,
    24,
    25,
    26,
    27,
    64,
    64,
    64,
    64,
    64,
    64,
    28,
    29,
    30,
    31,
    32,
    33,
    34,
    35,
    36,
    37,
    38,
    39,
    40,
    41,
    42,
    43,
    44,
    45,
    46,
    47,
    48,
    49,
    50,
    51,
    52,
    53,
    64,
    64,
    64,
    64,
    64};

#define BF_safe_atoi64(dst, src)                 \
    do {                                         \
        tmp = (unsigned char)(src);              \
        if ((unsigned int)(tmp -= 0x20) >= 0x60) \
            return -1;                           \
        tmp = BF_atoi64[tmp];                    \
        if (tmp > 63)                            \
            return -1;                           \
        (dst) = tmp;                             \
    } while (0)

static int BF_decode(BF_word* dst, const char* src, int size)
{
    unsigned char* dptr = (unsigned char*)dst;
    unsigned char* end = dptr + size;
    const unsigned char* sptr = (const unsigned char*)src;
    unsigned int tmp, c1, c2, c3, c4;

    do {
        BF_safe_atoi64(c1, *sptr++);
        BF_safe_atoi64(c2, *sptr++);
        *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
        if (dptr >= end)
            break;

        BF_safe_atoi64(c3, *sptr++);
        *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2);
        if (dptr >= end)
            break;

        BF_safe_atoi64(c4, *sptr++);
        *dptr++ = ((c3 & 0x03) << 6) | c4;
    } while (dptr < end);

    return 0;
}

static void BF_encode(char* dst, const BF_word* src, int size)
{
    const unsigned char* sptr = (const unsigned char*)src;
    const unsigned char* end = sptr + size;
    unsigned char* dptr = (unsigned char*)dst;
    unsigned int c1, c2;

    do {
        c1 = *sptr++;
        *dptr++ = BF_itoa64[c1 >> 2];
        c1 = (c1 & 0x03) << 4;
        if (sptr >= end) {
            *dptr++ = BF_itoa64[c1];
            break;
        }

        c2 = *sptr++;
        c1 |= c2 >> 4;
        *dptr++ = BF_itoa64[c1];
        c1 = (c2 & 0x0f) << 2;
        if (sptr >= end) {
            *dptr++ = BF_itoa64[c1];
            break;
        }

        c2 = *sptr++;
        c1 |= c2 >> 6;
        *dptr++ = BF_itoa64[c1];
        *dptr++ = BF_itoa64[c2 & 0x3f];
    } while (sptr < end);
}

static void BF_swap(BF_word* x, int count)
{
    /* Swap on little-endian hardware, else do nothing */
#ifndef WORDS_BIGENDIAN
    BF_word tmp;

    do {
        tmp = *x;
        tmp = (tmp << 16) | (tmp >> 16);
        *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
    } while (--count);
#endif
}

#if BF_SCALE
/* Architectures which can shift addresses left by 2 bits with no extra cost */
#define BF_ROUND(L, R, N)        \
    tmp1 = (L)&0xFF;             \
    tmp2 = (L) >> 8;             \
    tmp2 &= 0xFF;                \
    tmp3 = (L) >> 16;            \
    tmp3 &= 0xFF;                \
    tmp4 = (L) >> 24;            \
    tmp1 = data.ctx.S[3][tmp1];  \
    tmp2 = data.ctx.S[2][tmp2];  \
    tmp3 = data.ctx.S[1][tmp3];  \
    tmp3 += data.ctx.S[0][tmp4]; \
    tmp3 ^= tmp2;                \
    (R) ^= data.ctx.P[(N) + 1];  \
    tmp3 += tmp1;                \
    (R) ^= tmp3;
#else
/* Architectures with no complicated addressing modes supported */
#define BF_INDEX(S, i) (*((BF_word*)(((unsigned char*)(S)) + (i))))
#define BF_ROUND(L, R, N)                  \
    tmp1 = (L)&0xFF;                       \
    tmp1 <<= 2;                            \
    tmp2 = (L) >> 6;                       \
    tmp2 &= 0x3FC;                         \
    tmp3 = (L) >> 14;                      \
    tmp3 &= 0x3FC;                         \
    tmp4 = (L) >> 22;                      \
    tmp4 &= 0x3FC;                         \
    tmp1 = BF_INDEX(data.ctx.S[3], tmp1);  \
    tmp2 = BF_INDEX(data.ctx.S[2], tmp2);  \
    tmp3 = BF_INDEX(data.ctx.S[1], tmp3);  \
    tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \
    tmp3 ^= tmp2;                          \
    (R) ^= data.ctx.P[(N) + 1];            \
    tmp3 += tmp1;                          \
    (R) ^= tmp3;
#endif

/*
 * Encrypt one block, BF_N is hardcoded here.
 */
#define BF_ENCRYPT      \
    L ^= data.ctx.P[0]; \
    BF_ROUND(L, R, 0);  \
    BF_ROUND(R, L, 1);  \
    BF_ROUND(L, R, 2);  \
    BF_ROUND(R, L, 3);  \
    BF_ROUND(L, R, 4);  \
    BF_ROUND(R, L, 5);  \
    BF_ROUND(L, R, 6);  \
    BF_ROUND(R, L, 7);  \
    BF_ROUND(L, R, 8);  \
    BF_ROUND(R, L, 9);  \
    BF_ROUND(L, R, 10); \
    BF_ROUND(R, L, 11); \
    BF_ROUND(L, R, 12); \
    BF_ROUND(R, L, 13); \
    BF_ROUND(L, R, 14); \
    BF_ROUND(R, L, 15); \
    tmp4 = R;           \
    R = L;              \
    L = tmp4 ^ data.ctx.P[BF_N + 1];

#if BF_ASM

extern void _BF_body_r(BF_ctx* ctx);

#define BF_body() _BF_body_r(&data.ctx);
#else

#define BF_body()                          \
    L = R = 0;                             \
    ptr = data.ctx.P;                      \
    do {                                   \
        ptr += 2;                          \
        BF_ENCRYPT;                        \
        *(ptr - 2) = L;                    \
        *(ptr - 1) = R;                    \
    } while (ptr < &data.ctx.P[BF_N + 2]); \
                                           \
    ptr = data.ctx.S[0];                   \
    do {                                   \
        ptr += 2;                          \
        BF_ENCRYPT;                        \
        *(ptr - 2) = L;                    \
        *(ptr - 1) = R;                    \
    } while (ptr < &data.ctx.S[3][0xFF]);
#endif

static void BF_set_key(const char* key, BF_key expanded, BF_key initial, int sign_extension_bug)
{
    const char* ptr = key;
    int i, j;
    BF_word tmp;

    for (i = 0; i < BF_N + 2; i++) {
        tmp = 0;
        for (j = 0; j < 4; j++) {
            tmp <<= 8;
            if (sign_extension_bug)
                tmp |= (BF_word_signed)(signed char)*ptr;
            else
                tmp |= (unsigned char)*ptr;

            if (!*ptr)
                ptr = key;
            else
                ptr++;
        }

        expanded[i] = tmp;
        initial[i] = BF_init_state.P[i] ^ tmp;
    }
}

char* _crypt_blowfish_rn(const char* key, const char* setting, char* output, int size)
{
    struct {
        BF_ctx ctx;
        BF_key expanded_key;
        union {
            BF_word salt[4];
            BF_word output[6];
        } binary;
    } data;
    BF_word L, R;
    BF_word tmp1, tmp2, tmp3, tmp4;
    BF_word* ptr = NULL;
    BF_word count;
    int i;

    if (size < 7 + 22 + 31 + 1)
        return NULL;

    /*
     * Blowfish salt value must be formatted as follows: "$2a$" or "$2x$", a
     * two digit cost parameter, "$", and 22 digits from the alphabet
     * "./0-9A-Za-z". -- from the PHP crypt docs. Apparently we enforce a few
     * more restrictions on the count in the salt as well.
     */
    if (strlen(setting) < 29)
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid salt")));

    if (setting[0] != '$' || setting[1] != '2' || (setting[2] != 'a' && setting[2] != 'x') || setting[3] != '$' ||
        setting[4] < '0' || setting[4] > '3' || setting[5] < '0' || setting[5] > '9' ||
        (setting[4] == '3' && setting[5] > '1') || setting[6] != '$') {
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid salt")));
    }

    count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
    if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16)) {
        memset(data.binary.salt, 0, sizeof(data.binary.salt));
        ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid salt")));
    }
    BF_swap(data.binary.salt, 4);

    BF_set_key(key, data.expanded_key, data.ctx.P, setting[2] == 'x');

    memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S));

    L = R = 0;
    for (i = 0; i < BF_N + 2; i += 2) {
        L ^= data.binary.salt[i & 2];
        R ^= data.binary.salt[(i & 2) + 1];
        BF_ENCRYPT;
        data.ctx.P[i] = L;
        data.ctx.P[i + 1] = R;
    }

    ptr = data.ctx.S[0];
    do {
        ptr += 4;
        L ^= data.binary.salt[(BF_N + 2) & 3];
        R ^= data.binary.salt[(BF_N + 3) & 3];
        BF_ENCRYPT;
        *(ptr - 4) = L;
        *(ptr - 3) = R;

        L ^= data.binary.salt[(BF_N + 4) & 3];
        R ^= data.binary.salt[(BF_N + 5) & 3];
        BF_ENCRYPT;
        *(ptr - 2) = L;
        *(ptr - 1) = R;
    } while (ptr < &data.ctx.S[3][0xFF]);

    do {
        data.ctx.P[0] ^= data.expanded_key[0];
        data.ctx.P[1] ^= data.expanded_key[1];
        data.ctx.P[2] ^= data.expanded_key[2];
        data.ctx.P[3] ^= data.expanded_key[3];
        data.ctx.P[4] ^= data.expanded_key[4];
        data.ctx.P[5] ^= data.expanded_key[5];
        data.ctx.P[6] ^= data.expanded_key[6];
        data.ctx.P[7] ^= data.expanded_key[7];
        data.ctx.P[8] ^= data.expanded_key[8];
        data.ctx.P[9] ^= data.expanded_key[9];
        data.ctx.P[10] ^= data.expanded_key[10];
        data.ctx.P[11] ^= data.expanded_key[11];
        data.ctx.P[12] ^= data.expanded_key[12];
        data.ctx.P[13] ^= data.expanded_key[13];
        data.ctx.P[14] ^= data.expanded_key[14];
        data.ctx.P[15] ^= data.expanded_key[15];
        data.ctx.P[16] ^= data.expanded_key[16];
        data.ctx.P[17] ^= data.expanded_key[17];

        BF_body();

        tmp1 = data.binary.salt[0];
        tmp2 = data.binary.salt[1];
        tmp3 = data.binary.salt[2];
        tmp4 = data.binary.salt[3];
        data.ctx.P[0] ^= tmp1;
        data.ctx.P[1] ^= tmp2;
        data.ctx.P[2] ^= tmp3;
        data.ctx.P[3] ^= tmp4;
        data.ctx.P[4] ^= tmp1;
        data.ctx.P[5] ^= tmp2;
        data.ctx.P[6] ^= tmp3;
        data.ctx.P[7] ^= tmp4;
        data.ctx.P[8] ^= tmp1;
        data.ctx.P[9] ^= tmp2;
        data.ctx.P[10] ^= tmp3;
        data.ctx.P[11] ^= tmp4;
        data.ctx.P[12] ^= tmp1;
        data.ctx.P[13] ^= tmp2;
        data.ctx.P[14] ^= tmp3;
        data.ctx.P[15] ^= tmp4;
        data.ctx.P[16] ^= tmp1;
        data.ctx.P[17] ^= tmp2;

        BF_body();
    } while (--count);

    for (i = 0; i < 6; i += 2) {
        L = BF_magic_w[i];
        R = BF_magic_w[i + 1];

        count = 64;
        do {
            BF_ENCRYPT;
        } while (--count);

        data.binary.output[i] = L;
        data.binary.output[i + 1] = R;
    }

    memcpy(output, setting, 7 + 22 - 1);
    output[7 + 22 - 1] = BF_itoa64[(int)BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30];

    /* This has to be bug-compatible with the original implementation, so
     * only encode 23 of the 24 bytes. :-) */
    BF_swap(data.binary.output, 6);
    BF_encode(&output[7 + 22], data.binary.output, 23);
    output[7 + 22 + 31] = '\0';

    /* Overwrite the most obvious sensitive data we have on the stack. Note
     * that this does not guarantee there's no sensitive data left on the
     * stack and/or in registers; I'm not aware of portable code that does. */
    memset(&data, 0, sizeof(data));

    return output;
}