Skip to main content

c/
crypt_impl.rs

1// crypt_impl.rs - crypt password hashing (MD5, bcrypt, SHA-256, SHA-512)
2// Ported from musl libc src/crypt/
3
4unsafe fn cstr_bytes(s: *const c_char) -> &'static [u8] {
5    if s.is_null() { return &[]; }
6    let len = strlen(s as *const c_char);
7    core::slice::from_raw_parts(s as *const u8, len)
8}
9
10const CRYPT_B64: [u8; 64] = *b"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
11
12fn crypt_to64(out: &mut [u8], mut u: u32, n: usize) -> usize {
13    for i in 0..n {
14        out[i] = CRYPT_B64[(u % 64) as usize];
15        u /= 64;
16    }
17    n
18}
19
20// ============================================================
21// MD5
22// ============================================================
23
24struct Md5 { len: u64, h: [u32; 4], buf: [u8; 64] }
25
26const MD5_TAB: [u32; 64] = [
27    0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,
28    0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,0xa679438e,0x49b40821,
29    0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
30    0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,
31    0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,
32    0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,
33    0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,
34    0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391,
35];
36
37impl Md5 {
38    fn init(&mut self) {
39        self.len = 0;
40        self.h = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476];
41    }
42    fn processblock(&mut self, buf: &[u8; 64]) {
43        let mut w = [0u32; 16];
44        for i in 0..16 {
45            w[i] = buf[4*i] as u32 | (buf[4*i+1] as u32)<<8 | (buf[4*i+2] as u32)<<16 | (buf[4*i+3] as u32)<<24;
46        }
47        let (mut a,mut b,mut c,mut d) = (self.h[0],self.h[1],self.h[2],self.h[3]);
48        let mut i = 0usize;
49        while i < 16 {
50            a = a.wrapping_add((b&c|!b&d).wrapping_add(w[i]).wrapping_add(MD5_TAB[i])).rotate_left(7).wrapping_add(b); i+=1;
51            d = d.wrapping_add((a&b|!a&c).wrapping_add(w[i]).wrapping_add(MD5_TAB[i])).rotate_left(12).wrapping_add(a); i+=1;
52            c = c.wrapping_add((d&a|!d&b).wrapping_add(w[i]).wrapping_add(MD5_TAB[i])).rotate_left(17).wrapping_add(d); i+=1;
53            b = b.wrapping_add((c&d|!c&a).wrapping_add(w[i]).wrapping_add(MD5_TAB[i])).rotate_left(22).wrapping_add(c); i+=1;
54        }
55        while i < 32 {
56            a = a.wrapping_add((b&d|c&!d).wrapping_add(w[(5*i+1)%16]).wrapping_add(MD5_TAB[i])).rotate_left(5).wrapping_add(b); i+=1;
57            d = d.wrapping_add((a&c|b&!c).wrapping_add(w[(5*i+1)%16]).wrapping_add(MD5_TAB[i])).rotate_left(9).wrapping_add(a); i+=1;
58            c = c.wrapping_add((d&b|a&!b).wrapping_add(w[(5*i+1)%16]).wrapping_add(MD5_TAB[i])).rotate_left(14).wrapping_add(d); i+=1;
59            b = b.wrapping_add((c&a|d&!a).wrapping_add(w[(5*i+1)%16]).wrapping_add(MD5_TAB[i])).rotate_left(20).wrapping_add(c); i+=1;
60        }
61        while i < 48 {
62            a = a.wrapping_add((b^c^d).wrapping_add(w[(3*i+5)%16]).wrapping_add(MD5_TAB[i])).rotate_left(4).wrapping_add(b); i+=1;
63            d = d.wrapping_add((a^b^c).wrapping_add(w[(3*i+5)%16]).wrapping_add(MD5_TAB[i])).rotate_left(11).wrapping_add(a); i+=1;
64            c = c.wrapping_add((d^a^b).wrapping_add(w[(3*i+5)%16]).wrapping_add(MD5_TAB[i])).rotate_left(16).wrapping_add(d); i+=1;
65            b = b.wrapping_add((c^d^a).wrapping_add(w[(3*i+5)%16]).wrapping_add(MD5_TAB[i])).rotate_left(23).wrapping_add(c); i+=1;
66        }
67        while i < 64 {
68            a = a.wrapping_add((c^(b|!d)).wrapping_add(w[7*i%16]).wrapping_add(MD5_TAB[i])).rotate_left(6).wrapping_add(b); i+=1;
69            d = d.wrapping_add((b^(a|!c)).wrapping_add(w[7*i%16]).wrapping_add(MD5_TAB[i])).rotate_left(10).wrapping_add(a); i+=1;
70            c = c.wrapping_add((a^(d|!b)).wrapping_add(w[7*i%16]).wrapping_add(MD5_TAB[i])).rotate_left(15).wrapping_add(d); i+=1;
71            b = b.wrapping_add((d^(c|!a)).wrapping_add(w[7*i%16]).wrapping_add(MD5_TAB[i])).rotate_left(21).wrapping_add(c); i+=1;
72        }
73        self.h[0] = self.h[0].wrapping_add(a);
74        self.h[1] = self.h[1].wrapping_add(b);
75        self.h[2] = self.h[2].wrapping_add(c);
76        self.h[3] = self.h[3].wrapping_add(d);
77    }
78    fn update(&mut self, data: &[u8]) {
79        let mut p = 0usize;
80        let r = (self.len % 64) as usize;
81        self.len += data.len() as u64;
82        if r > 0 {
83            let avail = 64 - r;
84            if data.len() < avail { self.buf[r..r+data.len()].copy_from_slice(data); return; }
85            self.buf[r..64].copy_from_slice(&data[..avail]);
86            p = avail;
87            let b = self.buf; self.processblock(&b);
88        }
89        while p + 64 <= data.len() {
90            let mut blk = [0u8; 64]; blk.copy_from_slice(&data[p..p+64]); self.processblock(&blk); p += 64;
91        }
92        if p < data.len() { self.buf[..data.len()-p].copy_from_slice(&data[p..]); }
93    }
94    fn finish(&mut self, md: &mut [u8; 16]) {
95        let r = (self.len % 64) as usize;
96        self.buf[r] = 0x80;
97        if r + 1 > 56 { for i in r+1..64 { self.buf[i]=0; } let b=self.buf; self.processblock(&b); for i in 0..56 { self.buf[i]=0; } }
98        else { for i in r+1..56 { self.buf[i]=0; } }
99        let bits = self.len.wrapping_mul(8);
100        for i in 0..8 { self.buf[56+i] = (bits >> (i*8)) as u8; }
101        let b = self.buf; self.processblock(&b);
102        for i in 0..4 { md[4*i]=self.h[i] as u8; md[4*i+1]=(self.h[i]>>8) as u8; md[4*i+2]=(self.h[i]>>16) as u8; md[4*i+3]=(self.h[i]>>24) as u8; }
103    }
104}
105
106fn md5crypt(key: &[u8], setting: &[u8], output: &mut [u8]) -> Option<usize> {
107    if setting.len() < 3 || &setting[..3] != b"$1$" { return None; }
108    let klen = { let mut n=0usize; while n<key.len() && n<=30000 && key[n]!=0 { n+=1; } if n>30000 { return None; } n };
109    let slen = { let mut i=0usize; while i<8 && 3+i<setting.len() && setting[3+i]!=b'$' && setting[3+i]!=0 { i+=1; } i };
110    let salt = &setting[3..3+slen];
111    let mut ctx = Md5{len:0,h:[0;4],buf:[0;64]};
112    let mut md = [0u8; 16];
113    ctx.init(); ctx.update(&key[..klen]); ctx.update(salt); ctx.update(&key[..klen]); ctx.finish(&mut md);
114    ctx.init(); ctx.update(&key[..klen]); ctx.update(&setting[..3+slen]);
115    { let mut i=klen; while i>16 { ctx.update(&md); i-=16; } ctx.update(&md[..i]); }
116    { let saved=md[0]; md[0]=0; let mut i=klen; while i>0 { if i&1!=0 { ctx.update(&[0u8]); } else { ctx.update(&[key[0]]); } i>>=1; } md[0]=saved; }
117    ctx.finish(&mut md);
118    for i in 0..1000u32 {
119        ctx.init();
120        if i%2!=0 { ctx.update(&key[..klen]); } else { ctx.update(&md); }
121        if i%3!=0 { ctx.update(salt); }
122        if i%7!=0 { ctx.update(&key[..klen]); }
123        if i%2!=0 { ctx.update(&md); } else { ctx.update(&key[..klen]); }
124        ctx.finish(&mut md);
125    }
126    output[..3+slen].copy_from_slice(&setting[..3+slen]);
127    let mut p = 3+slen; output[p]=b'$'; p+=1;
128    static PERM: [[u8;3];5] = [[0,6,12],[1,7,13],[2,8,14],[3,9,15],[4,10,5]];
129    for j in 0..5 { let v=(md[PERM[j][0] as usize] as u32)<<16|(md[PERM[j][1] as usize] as u32)<<8|md[PERM[j][2] as usize] as u32; p+=crypt_to64(&mut output[p..],v,4); }
130    p+=crypt_to64(&mut output[p..],md[11] as u32,2);
131    output[p]=0;
132    Some(p)
133}
134
135const MD5_TK: &[u8] = b"Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !";
136const MD5_TS: &[u8] = b"$1$abcd0123$";
137const MD5_TH: &[u8] = b"$1$abcd0123$9Qcg8DyviekV3tDGMZynJ1";
138
139#[no_mangle]
140pub unsafe extern "C" fn __crypt_md5(key: *const c_char, setting: *const c_char, output: *mut c_char) -> *mut c_char {
141    let ks = cstr_bytes(key); let ss = cstr_bytes(setting);
142    let out = core::slice::from_raw_parts_mut(output as *mut u8, 256);
143    let mut tb = [0u8; 64]; let q = md5crypt(MD5_TK, MD5_TS, &mut tb);
144    let p = md5crypt(ks, ss, out);
145    if p.is_none() || q.is_none() || tb[..MD5_TH.len()] != *MD5_TH { *output=b'*' as c_char; *output.add(1)=0; return output; }
146    out[p.unwrap()]=0; output
147}
148
149// ============================================================
150// SHA-256
151// ============================================================
152
153struct Sha256 { len: u64, h: [u32; 8], buf: [u8; 64] }
154
155const SHA256_K: [u32; 64] = [
156    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
157    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
158    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
159    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
160    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
161    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
162    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
163    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2,
164];
165
166impl Sha256 {
167    fn init(&mut self) {
168        self.len = 0;
169        self.h = [0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19];
170    }
171    fn processblock(&mut self, buf: &[u8; 64]) {
172        let mut w = [0u32; 64];
173        for i in 0..16 { w[i]=(buf[4*i] as u32)<<24|(buf[4*i+1] as u32)<<16|(buf[4*i+2] as u32)<<8|buf[4*i+3] as u32; }
174        for i in 16..64 { let s0=w[i-15].rotate_right(7)^w[i-15].rotate_right(18)^(w[i-15]>>3); let s1=w[i-2].rotate_right(17)^w[i-2].rotate_right(19)^(w[i-2]>>10); w[i]=w[i-16].wrapping_add(s0).wrapping_add(w[i-7]).wrapping_add(s1); }
175        let (mut a,mut b,mut c,mut d,mut e,mut f,mut g,mut h)=(self.h[0],self.h[1],self.h[2],self.h[3],self.h[4],self.h[5],self.h[6],self.h[7]);
176        for i in 0..64 {
177            let s1=e.rotate_right(6)^e.rotate_right(11)^e.rotate_right(25); let ch=(e&f)^(!e&g); let t1=h.wrapping_add(s1).wrapping_add(ch).wrapping_add(SHA256_K[i]).wrapping_add(w[i]);
178            let s0=a.rotate_right(2)^a.rotate_right(13)^a.rotate_right(22); let maj=(a&b)^(a&c)^(b&c); let t2=s0.wrapping_add(maj);
179            h=g;g=f;f=e;e=d.wrapping_add(t1);d=c;c=b;b=a;a=t1.wrapping_add(t2);
180        }
181        self.h[0]=self.h[0].wrapping_add(a);self.h[1]=self.h[1].wrapping_add(b);self.h[2]=self.h[2].wrapping_add(c);self.h[3]=self.h[3].wrapping_add(d);
182        self.h[4]=self.h[4].wrapping_add(e);self.h[5]=self.h[5].wrapping_add(f);self.h[6]=self.h[6].wrapping_add(g);self.h[7]=self.h[7].wrapping_add(h);
183    }
184    fn update(&mut self, data: &[u8]) {
185        let mut p=0usize; let r=(self.len%64) as usize; self.len+=data.len() as u64;
186        if r>0 { let avail=64-r; if data.len()<avail { self.buf[r..r+data.len()].copy_from_slice(data); return; } self.buf[r..64].copy_from_slice(&data[..avail]); p=avail; let b=self.buf; self.processblock(&b); }
187        while p+64<=data.len() { let mut blk=[0u8;64]; blk.copy_from_slice(&data[p..p+64]); self.processblock(&blk); p+=64; }
188        if p<data.len() { self.buf[..data.len()-p].copy_from_slice(&data[p..]); }
189    }
190    fn finish(&mut self, md: &mut [u8; 32]) {
191        let r=(self.len%64) as usize; self.buf[r]=0x80;
192        if r+1>56 { for i in r+1..64 { self.buf[i]=0; } let b=self.buf; self.processblock(&b); for i in 0..56 { self.buf[i]=0; } }
193        else { for i in r+1..56 { self.buf[i]=0; } }
194        let bits=self.len.wrapping_mul(8);
195        for i in 0..8 { self.buf[56+i]=(bits>>(56-i*8)) as u8; }
196        let b=self.buf; self.processblock(&b);
197        for i in 0..8 { md[4*i]=(self.h[i]>>24) as u8; md[4*i+1]=(self.h[i]>>16) as u8; md[4*i+2]=(self.h[i]>>8) as u8; md[4*i+3]=self.h[i] as u8; }
198    }
199}
200
201fn sha256_hashmd(s: &mut Sha256, n: usize, md: &[u8]) {
202    let mut i=n; while i>32 { s.update(&md[..32]); i-=32; } s.update(&md[..i]);
203}
204
205fn sha256crypt(key: &[u8], setting: &[u8], output: &mut [u8]) -> Option<usize> {
206    if setting.len()<3 || &setting[..3]!=b"$5$" { return None; }
207    let klen = { let mut n=0usize; while n<key.len() && n<=256 && key[n]!=0 { n+=1; } if n>256 { return None; } n };
208    let mut salt_start=3usize;
209    let mut r: u32 = 5000;
210    let mut rounds_buf = [0u8; 24]; let mut rounds_len = 0usize;
211    if setting.len()>salt_start+7 && &setting[salt_start..salt_start+7]==b"rounds=" {
212        salt_start+=7;
213        if salt_start>=setting.len() || isdigit(setting[salt_start] as c_int)==0 { return None; }
214        let mut ep:*mut c_char=core::ptr::null_mut();
215        let u=unsafe{strtoul(setting[salt_start..].as_ptr() as *const c_char,&mut ep,10)};
216        let consumed=(ep as usize)-(setting[salt_start..].as_ptr() as usize);
217        if consumed==0 || setting.get(salt_start+consumed)!=Some(&b'$') { return None; }
218        salt_start+=consumed+1;
219        if u<1000 { r=1000; } else if u>9999999 { return None; } else { r=u as u32; }
220        rounds_buf[..7].copy_from_slice(b"rounds="); rounds_len=7;
221        let mut tmp=r; let mut db=[0u8;10]; let mut dl=0usize;
222        if tmp==0 { db[0]=b'0'; dl=1; } else { while tmp>0 { db[dl]=b'0'+(tmp%10) as u8; tmp/=10; dl+=1; } db[..dl].reverse(); }
223        rounds_buf[rounds_len..rounds_len+dl].copy_from_slice(&db[..dl]); rounds_len+=dl;
224        rounds_buf[rounds_len]=b'$'; rounds_len+=1;
225    }
226    let salt=&setting[salt_start..];
227    let slen={ let mut i=0usize; while i<16 && i<salt.len() && salt[i]!=b'$' && salt[i]!=0 { if salt[i]==b'\n'||salt[i]==b':' { return None; } i+=1; } i };
228    let sd=&salt[..slen];
229    let mut ctx=Sha256{len:0,h:[0;8],buf:[0;64]};
230    let mut md=[0u8;32]; let mut kmd=[0u8;32]; let mut smd=[0u8;32];
231    ctx.init(); ctx.update(&key[..klen]); ctx.update(sd); ctx.update(&key[..klen]); ctx.finish(&mut md);
232    ctx.init(); ctx.update(&key[..klen]); ctx.update(sd); sha256_hashmd(&mut ctx,klen,&md); { let mut i=klen; while i>0 { if i&1!=0{ctx.update(&md);}else{ctx.update(&key[..klen]);} i>>=1; } } ctx.finish(&mut md);
233    ctx.init(); for _ in 0..klen { ctx.update(&key[..klen]); } ctx.finish(&mut kmd);
234    ctx.init(); for _ in 0..16+md[0] as usize { ctx.update(sd); } ctx.finish(&mut smd);
235    for i in 0..r { ctx.init(); if i%2!=0{sha256_hashmd(&mut ctx,klen,&kmd);}else{ctx.update(&md);} if i%3!=0{ctx.update(&smd[..slen]);} if i%7!=0{sha256_hashmd(&mut ctx,klen,&kmd);} if i%2!=0{ctx.update(&md);}else{sha256_hashmd(&mut ctx,klen,&kmd);} ctx.finish(&mut md); }
236    let mut p=0usize;
237    output[p..p+3].copy_from_slice(b"$5$"); p+=3;
238    if rounds_len>0 { output[p..p+rounds_len].copy_from_slice(&rounds_buf[..rounds_len]); p+=rounds_len; }
239    output[p..p+slen].copy_from_slice(sd); p+=slen; output[p]=b'$'; p+=1;
240    static PERM:[[u8;3];10]=[[0,10,20],[21,1,11],[12,22,2],[3,13,23],[24,4,14],[15,25,5],[6,16,26],[27,7,17],[18,28,8],[9,19,29]];
241    for j in 0..10 { let v=(md[PERM[j][0]as usize]as u32)<<16|(md[PERM[j][1]as usize]as u32)<<8|md[PERM[j][2]as usize]as u32; p+=crypt_to64(&mut output[p..],v,4); }
242    p+=crypt_to64(&mut output[p..],((md[31]as u32)<<8)|md[30]as u32,3); output[p]=0; Some(p)
243}
244
245const S256_TK:&[u8]=b"Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !";
246const S256_TS:&[u8]=b"$5$rounds=1234$abc0123456789$";
247const S256_TH:&[u8]=b"$5$rounds=1234$abc0123456789$3VfDjPt05VHFn47C/ojFZ6KRPYrOjj1lLbH.dkF3bZ6";
248
249#[no_mangle]
250pub unsafe extern "C" fn __crypt_sha256(key:*const c_char,setting:*const c_char,output:*mut c_char)->*mut c_char {
251    let ks=cstr_bytes(key); let ss=cstr_bytes(setting);
252    let out=core::slice::from_raw_parts_mut(output as *mut u8,256);
253    let mut tb=[0u8;128]; let q=sha256crypt(S256_TK,S256_TS,&mut tb);
254    let p=sha256crypt(ks,ss,out);
255    if p.is_none()||q.is_none()||tb[..S256_TH.len()]!=*S256_TH { *output=b'*' as c_char; *output.add(1)=0; return output; }
256    out[p.unwrap()]=0; output
257}
258
259// ============================================================
260// SHA-512
261// ============================================================
262
263struct Sha512 { len: u64, h: [u64; 8], buf: [u8; 128] }
264
265const SHA512_K:[u64;80]=[
266    0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc,
267    0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118,
268    0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2,
269    0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694,
270    0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65,
271    0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5,
272    0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4,
273    0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70,
274    0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df,
275    0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b,
276    0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30,
277    0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8,
278    0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8,
279    0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3,
280    0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec,
281    0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b,
282    0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178,
283    0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b,
284    0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c,
285    0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817,
286];
287
288impl Sha512 {
289    fn init(&mut self) {
290        self.len=0;
291        self.h=[0x6a09e667f3bcc908,0xbb67ae8584caa73b,0x3c6ef372fe94f82b,0xa54ff53a5f1d36f1,
292                0x510e527fade682d1,0x9b05688c2b3e6c1f,0x1f83d9abfb41bd6b,0x5be0cd19137e2179];
293    }
294    fn processblock(&mut self, buf: &[u8; 128]) {
295        let mut w=[0u64;80];
296        for i in 0..16 { w[i]=(buf[8*i]as u64)<<56|(buf[8*i+1]as u64)<<48|(buf[8*i+2]as u64)<<40|(buf[8*i+3]as u64)<<32|(buf[8*i+4]as u64)<<24|(buf[8*i+5]as u64)<<16|(buf[8*i+6]as u64)<<8|buf[8*i+7]as u64; }
297        for i in 16..80 { let s0=w[i-15].rotate_right(1)^w[i-15].rotate_right(8)^(w[i-15]>>7); let s1=w[i-2].rotate_right(19)^w[i-2].rotate_right(61)^(w[i-2]>>6); w[i]=w[i-16].wrapping_add(s0).wrapping_add(w[i-7]).wrapping_add(s1); }
298        let (mut a,mut b,mut c,mut d,mut e,mut f,mut g,mut h)=(self.h[0],self.h[1],self.h[2],self.h[3],self.h[4],self.h[5],self.h[6],self.h[7]);
299        for i in 0..80 {
300            let s1=e.rotate_right(14)^e.rotate_right(18)^e.rotate_right(41); let ch=(e&f)^(!e&g); let t1=h.wrapping_add(s1).wrapping_add(ch).wrapping_add(SHA512_K[i]).wrapping_add(w[i]);
301            let s0=a.rotate_right(28)^a.rotate_right(34)^a.rotate_right(39); let maj=(a&b)^(a&c)^(b&c); let t2=s0.wrapping_add(maj);
302            h=g;g=f;f=e;e=d.wrapping_add(t1);d=c;c=b;b=a;a=t1.wrapping_add(t2);
303        }
304        self.h[0]=self.h[0].wrapping_add(a);self.h[1]=self.h[1].wrapping_add(b);self.h[2]=self.h[2].wrapping_add(c);self.h[3]=self.h[3].wrapping_add(d);
305        self.h[4]=self.h[4].wrapping_add(e);self.h[5]=self.h[5].wrapping_add(f);self.h[6]=self.h[6].wrapping_add(g);self.h[7]=self.h[7].wrapping_add(h);
306    }
307    fn update(&mut self, data: &[u8]) {
308        let mut p=0usize; let r=(self.len%128) as usize; self.len+=data.len() as u64;
309        if r>0 { let avail=128-r; if data.len()<avail { self.buf[r..r+data.len()].copy_from_slice(data); return; } self.buf[r..128].copy_from_slice(&data[..avail]); p=avail; let b=self.buf; self.processblock(&b); }
310        while p+128<=data.len() { let mut blk=[0u8;128]; blk.copy_from_slice(&data[p..p+128]); self.processblock(&blk); p+=128; }
311        if p<data.len() { self.buf[..data.len()-p].copy_from_slice(&data[p..]); }
312    }
313    fn finish(&mut self, md: &mut [u8; 64]) {
314        let r=(self.len%128) as usize; self.buf[r]=0x80;
315        if r+1>112 { for i in r+1..128 { self.buf[i]=0; } let b=self.buf; self.processblock(&b); for i in 0..120 { self.buf[i]=0; } }
316        else { for i in r+1..120 { self.buf[i]=0; } }
317        let bits=self.len.wrapping_mul(8);
318        for i in 0..8 { self.buf[120+i]=(bits>>(56-i*8)) as u8; }
319        let b=self.buf; self.processblock(&b);
320        for i in 0..8 { md[8*i]=(self.h[i]>>56)as u8; md[8*i+1]=(self.h[i]>>48)as u8; md[8*i+2]=(self.h[i]>>40)as u8; md[8*i+3]=(self.h[i]>>32)as u8; md[8*i+4]=(self.h[i]>>24)as u8; md[8*i+5]=(self.h[i]>>16)as u8; md[8*i+6]=(self.h[i]>>8)as u8; md[8*i+7]=self.h[i]as u8; }
321    }
322}
323
324fn sha512_hashmd(s: &mut Sha512, n: usize, md: &[u8]) {
325    let mut i=n; while i>64 { s.update(&md[..64]); i-=64; } s.update(&md[..i]);
326}
327
328fn sha512crypt(key: &[u8], setting: &[u8], output: &mut [u8]) -> Option<usize> {
329    if setting.len()<3 || &setting[..3]!=b"$6$" { return None; }
330    let klen = { let mut n=0usize; while n<key.len() && n<=256 && key[n]!=0 { n+=1; } if n>256 { return None; } n };
331    let mut salt_start=3usize;
332    let mut r: u32 = 5000;
333    let mut rounds_buf = [0u8; 24]; let mut rounds_len = 0usize;
334    if setting.len()>salt_start+7 && &setting[salt_start..salt_start+7]==b"rounds=" {
335        salt_start+=7;
336        if salt_start>=setting.len() || isdigit(setting[salt_start] as c_int)==0 { return None; }
337        let mut ep:*mut c_char=core::ptr::null_mut();
338        let u=unsafe{strtoul(setting[salt_start..].as_ptr() as *const c_char,&mut ep,10)};
339        let consumed=(ep as usize)-(setting[salt_start..].as_ptr() as usize);
340        if consumed==0 || setting.get(salt_start+consumed)!=Some(&b'$') { return None; }
341        salt_start+=consumed+1;
342        if u<1000 { r=1000; } else if u>9999999 { return None; } else { r=u as u32; }
343        rounds_buf[..7].copy_from_slice(b"rounds="); rounds_len=7;
344        let mut tmp=r; let mut db=[0u8;10]; let mut dl=0usize;
345        if tmp==0 { db[0]=b'0'; dl=1; } else { while tmp>0 { db[dl]=b'0'+(tmp%10) as u8; tmp/=10; dl+=1; } db[..dl].reverse(); }
346        rounds_buf[rounds_len..rounds_len+dl].copy_from_slice(&db[..dl]); rounds_len+=dl;
347        rounds_buf[rounds_len]=b'$'; rounds_len+=1;
348    }
349    let salt=&setting[salt_start..];
350    let slen={ let mut i=0usize; while i<16 && i<salt.len() && salt[i]!=b'$' && salt[i]!=0 { if salt[i]==b'\n'||salt[i]==b':' { return None; } i+=1; } i };
351    let sd=&salt[..slen];
352    let mut ctx=Sha512{len:0,h:[0;8],buf:[0;128]};
353    let mut md=[0u8;64]; let mut kmd=[0u8;64]; let mut smd=[0u8;64];
354    ctx.init(); ctx.update(&key[..klen]); ctx.update(sd); ctx.update(&key[..klen]); ctx.finish(&mut md);
355    ctx.init(); ctx.update(&key[..klen]); ctx.update(sd); sha512_hashmd(&mut ctx,klen,&md); { let mut i=klen; while i>0 { if i&1!=0{ctx.update(&md);}else{ctx.update(&key[..klen]);} i>>=1; } } ctx.finish(&mut md);
356    ctx.init(); for _ in 0..klen { ctx.update(&key[..klen]); } ctx.finish(&mut kmd);
357    ctx.init(); for _ in 0..16+md[0] as usize { ctx.update(sd); } ctx.finish(&mut smd);
358    for i in 0..r { ctx.init(); if i%2!=0{sha512_hashmd(&mut ctx,klen,&kmd);}else{ctx.update(&md);} if i%3!=0{ctx.update(&smd[..slen]);} if i%7!=0{sha512_hashmd(&mut ctx,klen,&kmd);} if i%2!=0{ctx.update(&md);}else{sha512_hashmd(&mut ctx,klen,&kmd);} ctx.finish(&mut md); }
359    let mut p=0usize;
360    output[p..p+3].copy_from_slice(b"$6$"); p+=3;
361    if rounds_len>0 { output[p..p+rounds_len].copy_from_slice(&rounds_buf[..rounds_len]); p+=rounds_len; }
362    output[p..p+slen].copy_from_slice(sd); p+=slen; output[p]=b'$'; p+=1;
363    static PERM:[[u8;3];21]=[[0,21,42],[22,43,1],[44,2,23],[3,24,45],[25,46,4],[47,5,26],[6,27,48],[28,49,7],[50,8,29],[9,30,51],[31,52,10],[53,11,32],[12,33,54],[34,55,13],[56,14,35],[15,36,57],[37,58,16],[59,17,38],[18,39,60],[40,61,19],[62,20,41]];
364    for j in 0..21 { let v=(md[PERM[j][0]as usize]as u32)<<16|(md[PERM[j][1]as usize]as u32)<<8|md[PERM[j][2]as usize]as u32; p+=crypt_to64(&mut output[p..],v,4); }
365    p+=crypt_to64(&mut output[p..],md[63] as u32,2); output[p]=0; Some(p)
366}
367
368const S512_TK:&[u8]=b"Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !";
369const S512_TS:&[u8]=b"$6$rounds=1234$abc0123456789$";
370const S512_TH:&[u8]=b"$6$rounds=1234$abc0123456789$BCpt8zLrc/RcyuXmCDOE1ALqMXB2MH6n1g891HhFj8.w7LxGv.FTkqq6Vxc/km3Y0jE0j24jY5PIv/oOu6reg1";
371
372#[no_mangle]
373pub unsafe extern "C" fn __crypt_sha512(key:*const c_char,setting:*const c_char,output:*mut c_char)->*mut c_char {
374    let ks=cstr_bytes(key); let ss=cstr_bytes(setting);
375    let out=core::slice::from_raw_parts_mut(output as *mut u8,256);
376    let mut tb=[0u8;128]; let q=sha512crypt(S512_TK,S512_TS,&mut tb);
377    let p=sha512crypt(ks,ss,out);
378    if p.is_none()||q.is_none()||tb[..S512_TH.len()]!=*S512_TH { *output=b'*' as c_char; *output.add(1)=0; return output; }
379    out[p.unwrap()]=0; output
380}
381
382// ============================================================
383// Blowfish (bcrypt)
384// ============================================================
385
386const BF_N: usize = 16;
387
388const BF_INIT_P: [u32; 18] = [
389    0x243f6a88,0x85a308d3,0x13198a2e,0x03707344,0xa4093822,0x299f31d0,0x082efa98,0xec4e6c89,
390    0x452821e6,0x38d01377,0xbe5466cf,0x34e90c6c,0xc0ac29b7,0xc97c50dd,0x3f84d5b5,0xb5470917,
391    0x9216d5d9,0x8979fb1b,
392];
393
394const BF_ITOA64: &[u8; 64] = b"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
395
396const BF_ATOI64: [u8; 0x60] = [
397    64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,1,
398    54,55,56,57,58,59,60,61,62,63,64,64,64,64,64,64,
399    64,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
400    17,18,19,20,21,22,23,24,25,26,27,64,64,64,64,64,
401    64,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,
402    43,44,45,46,47,48,49,50,51,52,53,64,64,64,64,64,
403];
404
405const BF_FLAGS_BY_SUBTYPE: [u8; 26] = [2,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,0];
406
407const BF_MAGIC_W: [u32; 6] = [0x4F727068, 0x65616E42, 0x65686F6C, 0x64657253, 0x63727944, 0x6F756274];
408
409// ponytail: Blowfish S-boxes stored as 4 flat arrays; total ~4KB static data
410const BF_S0: [u32; 256] = [
411    0xd1310ba6,0x98dfb5ac,0x2ffd72db,0xd01adfb7,0xb8e1afed,0x6a267e96,0xba7c9045,0xf12c7f99,
412    0x24a19947,0xb3916cf7,0x0801f2e2,0x858efc16,0x636920d8,0x71574e69,0xa458fea3,0xf4933d7e,
413    0x0d95748f,0x728eb658,0x718bcd58,0x82154aee,0x7b54a41d,0xc25a59b5,0x9c30d539,0x2af26013,
414    0xc5d1b023,0x286085f0,0xca417918,0xb8db38ef,0x8e79dcb0,0x603a180e,0x6c9e0e8b,0xb01e8a3e,
415    0xd71577c1,0xbd314b27,0x78af2fda,0x55605c60,0xe65525f3,0xaa55ab94,0x57489862,0x63e81440,
416    0x55ca396a,0x2aab10b6,0xb4cc5c34,0x1141e8ce,0xa15486af,0x7c72e993,0xb3ee1411,0x636fbc2a,
417    0x2ba9c55d,0x741831f6,0xce5c3e16,0x9b87931e,0xafd6ba33,0x6c24cf5c,0x7a325381,0x28958677,
418    0x3b8f4898,0x6b4bb9af,0xc4bfe81b,0x66282193,0x61d809cc,0xfb21a991,0x487cac60,0x5dec8032,
419    0xef845d5d,0xe98575b1,0xdc262302,0xeb651b88,0x23893e81,0xd396acc5,0x0f6d6ff3,0x83f44239,
420    0x2e0b4482,0xa4842004,0x69c8f04a,0x9e1f9b5e,0x21c66842,0xf6e96c9a,0x670c9c61,0xabd388f0,
421    0x6a51a0d2,0xd8542f68,0x960fa728,0xab5133a3,0x6eef0b6c,0x137a3be4,0xba3bf050,0x7efb2a98,
422    0xa1f1651d,0x39af0176,0x66ca593e,0x82430e88,0x8cee8619,0x456f9fb4,0x7d84a5c3,0x3b8b5ebe,
423    0xe06f75d8,0x85c12073,0x401a449f,0x56c16aa6,0x4ed3aa62,0x363f7706,0x1bfedf72,0x429b023d,
424    0x37d0d724,0xd00a1248,0xdb0fead3,0x49f1c09b,0x075372c9,0x80991b7b,0x25d479d8,0xf6e8def7,
425    0xe3fe501a,0xb6794c3b,0x976ce0bd,0x04c006ba,0xc1a94fb6,0x409f60c4,0x5e5c9ec2,0x196a2463,
426    0x68fb6faf,0x3e6c53b5,0x1339b2eb,0x3b52ec6f,0x6dfc511f,0x9b30952c,0xcc814544,0xaf5ebd09,
427    0xbee3d004,0xde334afd,0x660f2807,0x192e4bb3,0xc0cba857,0x45c8740f,0xd20b5f39,0xb9d3fbdb,
428    0x5579c0bd,0x1a60320a,0xd6a100c6,0x402c7279,0x679f25fe,0xfb1fa3cc,0x8ea5e9f8,0xdb3222f8,
429    0x3c7516df,0xfd616b15,0x2f501ec8,0xad0552ab,0x323db5fa,0xfd238760,0x53317b48,0x3e00df82,
430    0x9e5c57bb,0xca6f8ca0,0x1a87562e,0xdf1769db,0xd542a8f6,0x287effc3,0xac6732c6,0x8c4f5573,
431    0x695b27b0,0xbbca58c8,0xe1ffa35d,0xb8f011a0,0x10fa3d98,0xfd2183b8,0x4afcb56c,0x2dd1d35b,
432    0x9a53e479,0xb6f84565,0xd28e49bc,0x4bfb9790,0xe1ddf2da,0xa4cb7e33,0x62fb1341,0xcee4c6e8,
433    0xef20cada,0x36774c01,0xd07e9efe,0x2bf11fb4,0x95dbda4d,0xae909198,0xeaad8e71,0x6b93d5a0,
434    0xd08ed1d0,0xafc725e0,0x8e3c5b2f,0x8e7594b7,0x8ff6e2fb,0xf2122b64,0x8888b812,0x900df01c,
435    0x4fad5ea0,0x688fc31c,0xd1cff191,0xb3a8c1ad,0x2f2f2218,0xbe0e1777,0xea752dfe,0x8b021fa1,
436    0xe5a0cc0f,0xb56f74e8,0x18acf3d6,0xce89e299,0xb4a84fe0,0xfd13e0b7,0x7cc43b81,0xd2ada8d9,
437    0x165fa266,0x80957705,0x93cc7314,0x211a1477,0xe6ad2065,0x77b5fa86,0xc75442f5,0xfb9d35cf,
438    0xebcdaf0c,0x7b3e89a0,0xd6411bd3,0xae1e7e49,0x00250e2d,0x2071b35e,0x226800bb,0x57b8e0af,
439    0x2464369b,0xf009b91e,0x5563911d,0x59dfa6aa,0x78c14389,0xd95a537f,0x207d5ba2,0x02e5b9c5,
440    0x83260376,0x6295cfa9,0x11c81968,0x4e734a41,0xb3472dca,0x7b14a94a,0x1b510052,0x9a532915,
441    0xd60f573f,0xbc9bc6e4,0x2b60a476,0x81e67400,0x08ba6fb5,0x571be91f,0xf296ec6b,0x2a0dd915,
442    0xb6636521,0xe7b9f9b6,0xff34052e,0xc5855664,0x53b02d5d,0xa99f8fa1,0x08ba4799,0x6e85076a,
443];
444const BF_S1: [u32; 256] = [
445    0x4b7a70e9,0xb5b32944,0xdb75092e,0xc4192623,0xad6ea6b0,0x49a7df7d,0x9cee60b8,0x8fedb266,
446    0xecaa8c71,0x699a17ff,0x5664526c,0xc2b19ee1,0x193602a5,0x75094c29,0xa0591340,0xe4183a3e,
447    0x3f54989a,0x5b429d65,0x6b8fe4d6,0x99f73fd6,0xa1d29c07,0xefe830f5,0x4d2d38e6,0xf0255dc1,
448    0x4cdd2086,0x8470eb26,0x6382e9c6,0x021ecc5e,0x09686b3f,0x3ebaefc9,0x3c971814,0x6b6a70a1,
449    0x687f3584,0x52a0e286,0xb79c5305,0xaa500737,0x3e07841c,0x7fdeae5c,0x8e7d44ec,0x5716f2b8,
450    0xb03ada37,0xf0500c0d,0xf01c1f04,0x0200b3ff,0xae0cf51a,0x3cb574b2,0x25837a58,0xdc0921bd,
451    0xd19113f9,0x7ca92ff6,0x94324773,0x22f54701,0x3ae5e581,0x37c2dadc,0xc8b57634,0x9af3dda7,
452    0xa9446146,0x0fd0030e,0xecc8c73e,0xa4751e41,0xe238cd99,0x3bea0e2f,0x3280bba1,0x183eb331,
453    0x4e548b38,0x4f6db908,0x6f420d03,0xf60a04bf,0x2cb81290,0x24977c79,0x5679b072,0xbcaf89af,
454    0xde9a771f,0xd9930810,0xb38bae12,0xdccf3f2e,0x5512721f,0x2e6b7124,0x501adde6,0x9f84cd87,
455    0x7a584718,0x7408da17,0xbc9f9abc,0xe94b7d8c,0xec7aec3a,0xdb851dfa,0x63094366,0xc464c3d2,
456    0xef1c1847,0x3215d908,0xdd433b37,0x24c2ba16,0x12a14d43,0x2a65c451,0x50940002,0x133ae4dd,
457    0x71dff89e,0x10314e55,0x81ac77d6,0x5f11199b,0x043556f1,0xd7a3c76b,0x3c11183b,0x5924a509,
458    0xf28fe6ed,0x97f1fbfa,0x9ebabf2c,0x1e153c6e,0x86e34570,0xeae96fb1,0x860e5e0a,0x5a3e2ab3,
459    0x771fe71c,0x4e3d06fa,0x2965dcb9,0x99e71d0f,0x803e89d6,0x5266c825,0x2e4cc978,0x9c10b36a,
460    0xc6150eba,0x94e2ea78,0xa5fc3c53,0x1e0a2df4,0xf2f74ea7,0x361d2b3d,0x1939260f,0x19c27960,
461    0x5223a708,0xf71312b6,0xebadfe6e,0xeac31f66,0xe3bc4595,0xa67bc883,0xb17f37d1,0x018cff28,
462    0xc332ddef,0xbe6c5aa5,0x65582185,0x68ab9802,0xeecea50f,0xdb2f953b,0x2aef7dad,0x5b6e2f84,
463    0x1521b628,0x29076170,0xecdd4775,0x619f1510,0x13cca830,0xeb61bd96,0x0334fe1e,0xaa0363cf,
464    0xb5735c90,0x4c70a239,0xd59e9e0b,0xcbaade14,0xeecc86bc,0x60622ca7,0x9cab5cab,0xb2f3846e,
465    0x648b1eaf,0x19bdf0ca,0xa02369b9,0x655abb50,0x40685a32,0x3c2ab4b3,0x319ee9d5,0xc021b8f7,
466    0x9b540b19,0x875fa099,0x95f7997e,0x623d7da8,0xf837889a,0x97e32d77,0x11ed935f,0x16681281,
467    0x0e358829,0xc7e61fd6,0x96dedfa1,0x7858ba99,0x57f584a5,0x1b227263,0x9b83c3ff,0x1ac24696,
468    0xcdb30aeb,0x532e3054,0x8fd948e4,0x6dbc3128,0x58ebf2ef,0x34c6ffea,0xfe28ed61,0xee7c3c73,
469    0x5d4a14d9,0xe864b7e3,0x42105d14,0x203e13e0,0x45eee2b6,0xa3aaabea,0xdb6c4f15,0xfacb4fd0,
470    0xc742f442,0xef6abbb5,0x654f3b1d,0x41cd2105,0xd81e799e,0x86854dc7,0xe44b476a,0x3d816250,
471    0xcf62a1f2,0x5b8d2646,0xfc8883a0,0xc1c7b6a3,0x7f1524c3,0x69cb7492,0x47848a0b,0x5692b285,
472    0x095bbf00,0xad19489d,0x1462b174,0x23820e00,0x58428d2a,0x0c55f5ea,0x1dadf43e,0x233f7061,
473    0x3372f092,0x8d937e41,0xd65fecf1,0x6c223bdb,0x7cde3759,0xcbee7460,0x4085f2a7,0xce77326e,
474    0xa6078084,0x19f8509e,0xe8efd855,0x61d99735,0xa969a7aa,0xc50c06c2,0x5a04abfc,0x800bcadc,
475    0x9e447a2e,0xc3453484,0xfdd56705,0x0e1e9ec9,0xdb73dbd3,0x105588cd,0x675fda79,0xe3674340,
476    0xc5c43465,0x713e38d8,0x3d28f89e,0xf16dff20,0x153e21e7,0x8fb03d4a,0xe6e39f2b,0xdb83adf7,
477];
478const BF_S2: [u32; 256] = [
479    0xe93d5a68,0x948140f7,0xf64c261c,0x94692934,0x411520f7,0x7602d4f7,0xbcf46b2e,0xd4a20068,
480    0xd4082471,0x3320f46a,0x43b7d4b7,0x500061af,0x1e39f62e,0x97244546,0x14214f74,0xbf8b8840,
481    0x4d95fc1d,0x96b591af,0x70f4ddd3,0x66a02f45,0xbfbc09ec,0x03bd9785,0x7fac6dd0,0x31cb8504,
482    0x96eb27b3,0x55fd3941,0xda2547e6,0xabca0a9a,0x28507825,0x530429f4,0x0a2c86da,0xe9b66dfb,
483    0x68dc1462,0xd7486900,0x680ec0a4,0x27a18dee,0x4f3ffea2,0xe887ad8c,0xb58ce006,0x7af4d6b6,
484    0xaace1e7c,0xd3375fec,0xce78a399,0x406b2a42,0x20fe9e35,0xd9f385b9,0xee39d7ab,0x3b124e8b,
485    0x1dc9faf7,0x4b6d1856,0x26a36631,0xeae397b2,0x3a6efa74,0xdd5b4332,0x6841e7f7,0xca7820fb,
486    0xfb0af54e,0xd8feb397,0x454056ac,0xba489527,0x55533a3a,0x20838d87,0xfe6ba9b7,0xd096954b,
487    0x55a867bc,0xa1159a58,0xcca92963,0x99e1db33,0xa62a4a56,0x3f3125f9,0x5ef47e1c,0x9029317c,
488    0xfdf8e802,0x04272f70,0x80bb155c,0x05282ce3,0x95c11548,0xe4c66d22,0x48c1133f,0xc70f86dc,
489    0x07f9c9ee,0x41041f0f,0x404779a4,0x5d886e17,0x325f51eb,0xd59bc0d1,0xf2bcc18f,0x41113564,
490    0x257b7834,0x602a9c60,0xdff8e8a3,0x1f636c1b,0x0e12b4c2,0x02e1329e,0xaf664fd1,0xcad18115,
491    0x6b2395e0,0x333e92e1,0x3b240b62,0xeebeb922,0x85b2a20e,0xe6ba0d99,0xde720c8c,0x2da2f728,
492    0xd0127845,0x95b794fd,0x647d0862,0xe7ccf5f0,0x5449a36f,0x877d48fa,0xc39dfd27,0xf33e8d1e,
493    0x0a476341,0x992eff74,0x3a6f6eab,0xf4f8fd37,0xa812dc60,0xa1ebddf8,0x991be14c,0xdb6e6b0d,
494    0xc67b5510,0x6d672c37,0x2765d43b,0xdcd0e804,0xf1290dc7,0xcc00ffa3,0xb5390f92,0x690fed0b,
495    0x667b9ffb,0xcedb7d9c,0xa091cf0b,0xd9155ea3,0xbb132f88,0x515bad24,0x7b9479bf,0x763bd6eb,
496    0x37392eb3,0xcc115979,0x8026e297,0xf42e312d,0x6842ada7,0xc66a2b3b,0x12754ccc,0x782ef11c,
497    0x6a124237,0xb79251e7,0x06a1bbe6,0x4bfb6350,0x1a6b1018,0x11caedfa,0x3d25bdd8,0xe2e1c3c9,
498    0x44421659,0x0a121386,0xd90cec6e,0xd5abea2a,0x64af674e,0xda86a85f,0xbebfe988,0x64e4c3fe,
499    0x9dbc8057,0xf0f7c086,0x60787bf8,0x6003604d,0xd1fd8346,0xf6381fb0,0x7745ae04,0xd736fccc,
500    0x83426b33,0xf01eab71,0xb0804187,0x3c005e5f,0x77a057be,0xbde8ae24,0x55464299,0xbf582e61,
501    0x4e58f48f,0xf2ddfda2,0xf474ef38,0x8789bdc2,0x5366f9c3,0xc8b38e74,0xb475f255,0x46fcd9b9,
502    0x7aeb2661,0x8b1ddf84,0x846a0e79,0x915f95e2,0x466e598e,0x20b45770,0x8cd55591,0xc902de4c,
503    0xb90bace1,0xbb8205d0,0x11a86248,0x7574a99e,0xb77f19b6,0xe0a9dc09,0x662d09a1,0xc4324633,
504    0xe85a1f02,0x09f0be8c,0x4a99a025,0x1d6efe10,0x1ab93d1d,0x0ba5a4df,0xa186f20f,0x2868f169,
505    0xdcb7da83,0x573906fe,0xa1e2ce9b,0x4fcd7f52,0x50115e01,0xa70683fa,0xa002b5c4,0x0de6d027,
506    0x9af88c27,0x773f8641,0xc3604c06,0x61a806b5,0xf0177a28,0xc0f586e0,0x006058aa,0x30dc7d62,
507    0x11e69ed7,0x2338ea63,0x53c2dd94,0xc2c21634,0xbbcbee56,0x90bcb6de,0xebfc7da1,0xce591d76,
508    0x6f05e409,0x4b7c0188,0x39720a3d,0x7c927c24,0x86e3725f,0x724d9db9,0x1ac15bb4,0xd39eb8fc,
509    0xed545578,0x08fca5b5,0xd83d7cd3,0x4dad0fc4,0x1e50ef5e,0xb161e6f8,0xa28514d9,0x6c51133c,
510    0x6fd5c7e7,0x56e14ec4,0x362abfce,0xddc6c837,0xd79a3234,0x92638212,0x670efa8e,0x406000e0,
511];
512const BF_S3: [u32; 256] = [
513    0x3a39ce37,0xd3faf5cf,0xabc27737,0x5ac52d1b,0x5cb0679e,0x4fa33742,0xd3822740,0x99bc9bbe,
514    0xd5118e9d,0xbf0f7315,0xd62d1c7e,0xc700c47b,0xb78c1b6b,0x21a19045,0xb26eb1be,0x6a366eb4,
515    0x5748ab2f,0xbc946e79,0xc6a376d2,0x6549c2c8,0x530ff8ee,0x468dde7d,0xd5730a1d,0x4cd04dc6,
516    0x2939bbdb,0xa9ba4650,0xac9526e8,0xbe5ee304,0xa1fad5f0,0x6a2d519a,0x63ef8ce2,0x9a86ee22,
517    0xc089c2b8,0x43242ef6,0xa51e03aa,0x9cf2d0a4,0x83c061ba,0x9be96a4d,0x8fe51550,0xba645bd6,
518    0x2826a2f9,0xa73a3ae1,0x4ba99586,0xef5562e9,0xc72fefd3,0xf752f7da,0x3f046f69,0x77fa0a59,
519    0x80e4a915,0x87b08601,0x9b09e6ad,0x3b3ee593,0xe990fd5a,0x9e34d797,0x2cf0b7d9,0x022b8b51,
520    0x96d5ac3a,0x017da67d,0xd1cf3ed6,0x7c7d2d28,0x1f9f25cf,0xadf2b89b,0x5ad6b472,0x5a88f54c,
521    0xe029ac71,0xe019a5e6,0x47b0acfd,0xed93fa9b,0xe8d3c48d,0x283b57cc,0xf8d56629,0x79132e28,
522    0x785f0191,0xed756055,0xf7960e44,0xe3d35e8c,0x15056dd4,0x88f46dba,0x03a16125,0x0564f0bd,
523    0xc3eb9e15,0x3c9057a2,0x97271aec,0xa93a072a,0x1b3f6d9b,0x1e6321f5,0xf59c66fb,0x26dcf319,
524    0x7533d928,0xb155fdf5,0x03563482,0x8aba3cbb,0x28517711,0xc20ad9f8,0xabcc5167,0xccad925f,
525    0x4de81751,0x3830dc8e,0x379d5862,0x9320f991,0xea7a90c2,0xfb3e7bce,0x5121ce64,0x774fbe32,
526    0xa8b6e37e,0xc3293d46,0x48de5369,0x6413e680,0xa2ae0810,0xdd6db224,0x69852dfd,0x09072166,
527    0xb39a460a,0x6445c0dd,0x586cdecf,0x1c20c8ae,0x5bbef7dd,0x1b588d40,0xccd2017f,0x6bb4e3bb,
528    0xdda26a7e,0x3a59ff45,0x3e350a44,0xbcb4cdd5,0x72eacea8,0xfa6484bb,0x8d6612ae,0xbf3c6f47,
529    0xd29be463,0x542f5d9e,0xaec2771b,0xf64e6370,0x740e0d8d,0xe75b1357,0xf8721671,0xaf537d5d,
530    0x4040cb08,0x4eb4e2cc,0x34d2466a,0x0115af84,0xe1b00428,0x95983a1d,0x06b89fb4,0xce6ea048,
531    0x6f3f3b82,0x3520ab82,0x011a1d4b,0x277227f8,0x611560b1,0xe7933fdc,0xbb3a792b,0x344525bd,
532    0xa08839e1,0x51ce794b,0x2f32c9b7,0xa01fbac9,0xe01cc87e,0xbcc7d1f6,0xcf0111c3,0xa1e8aac7,
533    0x1a908749,0xd44fbd9a,0xd0dadecb,0xd50ada38,0x0339c32a,0xc6913667,0x8df9317c,0xe0b12b4f,
534    0xf79e59b7,0x43f5bb3a,0xf2d519ff,0x27d9459c,0xbf97222c,0x15e6fc2a,0x0f91fc71,0x9b941525,
535    0xfae59361,0xceb69ceb,0xc2a86459,0x12baa8d1,0xb6c1075e,0xe3056a0c,0x10d25065,0xcb03a442,
536    0xe0ec6e0e,0x1698db3b,0x4c98a0be,0x3278e964,0x9f1f9532,0xe0d392df,0xd3a0342b,0x8971f21e,
537    0x1b0a7441,0x4ba3348c,0xc5be7120,0xc37632d8,0xdf359f8d,0x9b992f2e,0xe60b6f47,0x0fe3f11d,
538    0xe54cda54,0x1edad891,0xce6279cf,0xcd3e7e6f,0x1618b166,0xfd2c1d05,0x848fd2c5,0xf6fb2299,
539    0xf523f357,0xa6327623,0x93a83531,0x56cccd02,0xacf08162,0x5a75ebb5,0x6e163697,0x88d273cc,
540    0xde966292,0x81b949d0,0x4c50901b,0x71c65614,0xe6c6c7bd,0x327a140a,0x45e1d006,0xc3f27b9a,
541    0xc9aa53fd,0x62a80f00,0xbb25bfe2,0x35bdd2f6,0x71126905,0xb2040222,0xb6cbcf7c,0xcd769c2b,
542    0x53113ec0,0x1640e3d3,0x38abbd60,0x2547adf0,0xba38209c,0xf746ce76,0x77afa1c5,0x20756060,
543    0x85cbfe4e,0x8ae88dd8,0x7aaaf9b0,0x4cf9aa7e,0x1948c25c,0x02fb8a8c,0x01c36ae4,0xd6ebe1f9,
544    0x90d4f869,0xa65cdea0,0x3f09252d,0xc208e69f,0xb74e6132,0xce77e25b,0x578fdfe3,0x3ac372e6,
545];
546
547#[inline(always)]
548fn bf_encrypt_block(ps: &[u32; 1042], mut l: u32, mut r: u32) -> (u32, u32) {
549    let p = ps.as_ptr();
550    let s0 = unsafe { p.add(18) };
551    let s1 = unsafe { p.add(274) };
552    let s2 = unsafe { p.add(530) };
553    let s3 = unsafe { p.add(786) };
554    l ^= unsafe { *p };
555    for i in (0..BF_N).step_by(2) {
556        let mut tmp = unsafe { *s0.add((l >> 24) as usize) };
557        tmp = tmp.wrapping_add(unsafe { *s1.add(((l >> 16) & 0xFF) as usize) });
558        tmp ^= unsafe { *s2.add(((l >> 8) & 0xFF) as usize) };
559        tmp = tmp.wrapping_add(unsafe { *s3.add((l & 0xFF) as usize) });
560        r ^= unsafe { *p.add(i + 1) }; r ^= tmp;
561        let tl = r; r = l; l = tl;
562
563        let mut tmp2 = unsafe { *s0.add((l >> 24) as usize) };
564        tmp2 = tmp2.wrapping_add(unsafe { *s1.add(((l >> 16) & 0xFF) as usize) });
565        tmp2 ^= unsafe { *s2.add(((l >> 8) & 0xFF) as usize) };
566        tmp2 = tmp2.wrapping_add(unsafe { *s3.add((l & 0xFF) as usize) });
567        r ^= unsafe { *p.add(i + 2) }; r ^= tmp2;
568        let tl2 = r; r = l; l = tl2;
569    }
570    let old_r = r ^ unsafe { *p.add(BF_N + 1) };
571    r = l;
572    l = old_r;
573    (l, r)
574}
575
576fn bf_crypt_inner(key: &[u8], setting: &[u8], output: &mut [u8], min: u32) -> Option<usize> {
577    if setting.len() < 7 { return None; }
578    if setting[0] != b'$' || setting[1] != b'2' { return None; }
579    let subtype = setting[2];
580    if subtype < b'a' || subtype > b'z' { return None; }
581    let st_idx = (subtype - b'a') as usize;
582    if st_idx >= 26 || BF_FLAGS_BY_SUBTYPE[st_idx] == 0 { return None; }
583    if setting[3] != b'$' { return None; }
584    if setting[4] < b'0' || setting[4] > b'1' { return None; }
585    if setting[5] < b'0' || setting[5] > b'9' { return None; }
586    if setting[6] != b'$' { return None; }
587
588    let count = 1u32 << (((setting[4] - b'0') as u32) * 10 + ((setting[5] - b'0') as u32));
589    if count < min { return None; }
590
591    if setting.len() < 7 + 22 { return None; }
592    let mut salt_bytes = [0u8; 16];
593    if bf_decode(&mut salt_bytes, &setting[7..7+22]) { return None; }
594    let salt_words = [
595        (salt_bytes[0] as u32) << 24 | (salt_bytes[1] as u32) << 16 | (salt_bytes[2] as u32) << 8 | salt_bytes[3] as u32,
596        (salt_bytes[4] as u32) << 24 | (salt_bytes[5] as u32) << 16 | (salt_bytes[6] as u32) << 8 | salt_bytes[7] as u32,
597        (salt_bytes[8] as u32) << 24 | (salt_bytes[9] as u32) << 16 | (salt_bytes[10] as u32) << 8 | salt_bytes[11] as u32,
598        (salt_bytes[12] as u32) << 24 | (salt_bytes[13] as u32) << 16 | (salt_bytes[14] as u32) << 8 | salt_bytes[15] as u32,
599    ];
600
601    let flags = BF_FLAGS_BY_SUBTYPE[st_idx];
602    let mut expanded = [0u32; 18];
603    let mut initial = [0u32; 18];
604    bf_set_key(key, &mut expanded, &mut initial, flags);
605
606    let mut ps = [0u32; 18 + 4 * 256];
607    ps[..18].copy_from_slice(&initial);
608    ps[18..274].copy_from_slice(&BF_S0);
609    ps[274..530].copy_from_slice(&BF_S1);
610    ps[530..786].copy_from_slice(&BF_S2);
611    ps[786..1042].copy_from_slice(&BF_S3);
612
613    let (mut l, mut r) = (0u32, 0u32);
614    let mut i = 0usize;
615    while i < ps.len() {
616        let (nl, nr) = bf_encrypt_block(&ps, l ^ salt_words[0], r ^ salt_words[1]);
617        ps[i] = nl;
618        ps[i + 1] = nr;
619        l = nl; r = nr;
620        i += 2;
621        if i >= ps.len() { break; }
622        let (nl2, nr2) = bf_encrypt_block(&ps, l ^ salt_words[2], r ^ salt_words[3]);
623        ps[i] = nl2;
624        ps[i + 1] = nr2;
625        l = nl2; r = nr2;
626        i += 2;
627    }
628
629    for _ in 0..count {
630        for i in 0..BF_N + 2 {
631            ps[i] ^= expanded[i];
632        }
633        bf_encrypt_full(&mut ps, 0, 0);
634        for i in (0..BF_N).step_by(4) {
635            ps[i] ^= salt_words[0];
636            ps[i + 1] ^= salt_words[1];
637            ps[i + 2] ^= salt_words[2];
638            ps[i + 3] ^= salt_words[3];
639        }
640        ps[16] ^= salt_words[0];
641        ps[17] ^= salt_words[1];
642        bf_encrypt_full(&mut ps, 0, 0);
643    }
644
645    // Final 64 Blowfish encryptions of magic string
646    let mut output_words = [0u32; 6];
647    for i in (0..6).step_by(2) {
648        let mut l = BF_MAGIC_W[i];
649        let mut r = BF_MAGIC_W[i + 1];
650        for _ in 0..64 {
651            let (nl, nr) = bf_encrypt_block(&ps, l, r);
652            l = nl; r = nr;
653        }
654        output_words[i] = l;
655        output_words[i + 1] = r;
656    }
657
658    // Format output
659    output[..7 + 22 - 1].copy_from_slice(&setting[..7 + 22 - 1]);
660    output[7 + 22 - 1] = BF_ITOA64[(BF_ATOI64[setting[7 + 22 - 1] as usize - 0x20] & 0x30) as usize];
661    for w in output_words.iter_mut() { *w = w.swap_bytes(); }
662    let enc_src: &[u8] = unsafe { core::slice::from_raw_parts(output_words.as_ptr() as *const u8, 24) };
663    bf_encode(&mut output[7 + 22..], &enc_src[..23]);
664    output[7 + 22 + 31] = 0;
665    Some(7 + 22 + 31)
666}
667
668// Encrypt (l,r) through all 1042 entries of PS array (BF_encrypt with start=&PS[0], end=&PS[PS_SIZE])
669#[inline(always)]
670fn bf_encrypt_full(ps: &mut [u32; 1042], mut l: u32, mut r: u32) {
671    let p = ps.as_mut_ptr();
672    let s0 = unsafe { p.add(18) };
673    let s1 = unsafe { p.add(274) };
674    let s2 = unsafe { p.add(530) };
675    let s3 = unsafe { p.add(786) };
676    let mut ptr = 0usize;
677    while ptr < 1042 {
678        l ^= unsafe { *p };
679        for i in (0..16).step_by(2) {
680            let mut tmp = unsafe { *s0.add((l >> 24) as usize) };
681            tmp = tmp.wrapping_add(unsafe { *s1.add(((l >> 16) & 0xFF) as usize) });
682            tmp ^= unsafe { *s2.add(((l >> 8) & 0xFF) as usize) };
683            tmp = tmp.wrapping_add(unsafe { *s3.add((l & 0xFF) as usize) });
684            r ^= unsafe { *p.add(i + 1) }; r ^= tmp;
685            let tl = r; r = l; l = tl;
686
687            let mut tmp2 = unsafe { *s0.add((l >> 24) as usize) };
688            tmp2 = tmp2.wrapping_add(unsafe { *s1.add(((l >> 16) & 0xFF) as usize) });
689            tmp2 ^= unsafe { *s2.add(((l >> 8) & 0xFF) as usize) };
690            tmp2 = tmp2.wrapping_add(unsafe { *s3.add((l & 0xFF) as usize) });
691            r ^= unsafe { *p.add(i + 2) }; r ^= tmp2;
692            let tl2 = r; r = l; l = tl2;
693        }
694        let old_r = r ^ unsafe { *p.add(BF_N + 1) };
695        r = l;
696        l = old_r;
697        unsafe {
698            *p.add(ptr) = l;
699            *p.add(ptr + 1) = r;
700        }
701        ptr += 2;
702    }
703}
704
705fn bf_set_key(key: &[u8], expanded: &mut [u32; 18], initial: &mut [u32; 18], flags: u8) {
706    let bug = flags & 1;
707    let safety: u32 = ((flags & 2) as u32) << 15;
708    let mut sign: u32 = 0;
709    let mut diff: u32 = 0;
710    let mut ptr = 0usize;
711    let klen = key.len();
712
713    for i in 0..BF_N + 2 {
714        let mut tmp = [0u32; 2];
715        for j in 0..4 {
716            let b = key[ptr];
717            tmp[0] = (tmp[0] << 8) | (b as u32);
718            tmp[1] = (tmp[1] << 8) | ((b as i8 as i32) as u32);
719            if j != 0 { sign |= tmp[1] & 0x80; }
720            if b == 0 {
721                ptr = 0;
722            } else {
723                ptr += 1;
724                if ptr >= klen { ptr = 0; }
725            }
726        }
727        diff |= tmp[0] ^ tmp[1];
728        expanded[i] = tmp[bug as usize];
729        initial[i] = BF_INIT_P[i] ^ tmp[bug as usize];
730    }
731
732    diff |= diff >> 16;
733    diff &= 0xffff;
734    diff = diff.wrapping_add(0xffff);
735    sign <<= 9;
736    sign &= !diff & safety;
737    initial[0] ^= sign;
738}
739
740fn bf_decode(dst: &mut [u8], src: &[u8]) -> bool {
741    let mut di = 0usize;
742    let mut si = 0usize;
743    while di < dst.len() {
744        if si + 1 >= src.len() { return true; }
745        let c1 = src[si] as usize;
746        let c2 = src[si + 1] as usize;
747        if c1 < 0x20 || c1 >= 0x80 || c2 < 0x20 || c2 >= 0x80 { return true; }
748        let v1 = BF_ATOI64[c1 - 0x20];
749        let v2 = BF_ATOI64[c2 - 0x20];
750        if v1 > 63 || v2 > 63 { return true; }
751        dst[di] = (v1 << 2) | ((v2 & 0x30) >> 4);
752        di += 1;
753        si += 2;
754        if di >= dst.len() { break; }
755
756        if si >= src.len() { return true; }
757        let c3 = src[si] as usize;
758        si += 1;
759        if c3 < 0x20 || c3 >= 0x80 { return true; }
760        let v3 = BF_ATOI64[c3 - 0x20];
761        if v3 > 63 { return true; }
762        dst[di] = ((v2 & 0x0F) << 4) | ((v3 & 0x3C) >> 2);
763        di += 1;
764        if di >= dst.len() { break; }
765
766        if si >= src.len() { return true; }
767        let c4 = src[si] as usize;
768        si += 1;
769        if c4 < 0x20 || c4 >= 0x80 { return true; }
770        let v4 = BF_ATOI64[c4 - 0x20];
771        if v4 > 63 { return true; }
772        dst[di] = ((v3 & 0x03) << 6) | v4;
773        di += 1;
774    }
775    false
776}
777
778fn bf_encode(dst: &mut [u8], src: &[u8]) {
779    let mut di = 0usize;
780    let mut si = 0usize;
781    while si < src.len() {
782        let c1 = src[si] as usize;
783        dst[di] = BF_ITOA64[c1 >> 2]; di += 1;
784        let c1_left = (c1 & 0x03) << 4;
785        si += 1;
786        if si >= src.len() { dst[di] = BF_ITOA64[c1_left]; break; }
787        let c2 = src[si] as usize;
788        dst[di] = BF_ITOA64[c1_left | (c2 >> 4)]; di += 1;
789        let c2_left = (c2 & 0x0f) << 2;
790        si += 1;
791        if si >= src.len() { dst[di] = BF_ITOA64[c2_left]; break; }
792        let c3 = src[si] as usize;
793        dst[di] = BF_ITOA64[c2_left | (c3 >> 6)]; di += 1;
794        dst[di] = BF_ITOA64[c3 & 0x3f]; di += 1;
795        si += 1;
796    }
797}
798
799#[no_mangle]
800pub unsafe extern "C" fn __crypt_blowfish(key: *const c_char, setting: *const c_char, output: *mut c_char) -> *mut c_char {
801    let ks = cstr_bytes(key);
802    let ss = cstr_bytes(setting);
803    let out = core::slice::from_raw_parts_mut(output as *mut u8, 256);
804
805    let mut key_buf = [0u8; 128];
806    if ks.len() >= key_buf.len() {
807        *output = b'*' as c_char;
808        *output.add(1) = 0;
809        return output;
810    }
811    key_buf[..ks.len()].copy_from_slice(ks);
812
813    let retval = bf_crypt_inner(&key_buf[..ks.len() + 1], ss, out, 16);
814    if retval.is_some() {
815        out[retval.unwrap()] = 0;
816        return output;
817    }
818    *output = b'*' as c_char;
819    *output.add(1) = 0;
820    output
821}
822
823// ============================================================
824// crypt_r / crypt
825// ============================================================
826
827#[no_mangle]
828pub unsafe extern "C" fn __crypt_r(key: *const c_char, setting: *const c_char, data: *mut crate::c_void) -> *mut c_char {
829    let output = data as *mut c_char;
830    let s = setting as *const u8;
831    if *s == b'$' && *s.add(1) != 0 && *s.add(2) != 0 {
832        if *s.add(1) == b'1' && *s.add(2) == b'$' {
833            return __crypt_md5(key, setting, output);
834        }
835        if *s.add(1) == b'2' && *s.add(3) == b'$' {
836            return __crypt_blowfish(key, setting, output);
837        }
838        if *s.add(1) == b'5' && *s.add(2) == b'$' {
839            return __crypt_sha256(key, setting, output);
840        }
841        if *s.add(1) == b'6' && *s.add(2) == b'$' {
842            return __crypt_sha512(key, setting, output);
843        }
844    }
845    if crate::crypt_des(key as *const u8, setting as *const u8, output as *mut u8) != 0 {
846        return output;
847    }
848    if *setting == b'*' as c_char {
849        *output = b'x' as c_char;
850    } else {
851        *output = b'*' as c_char;
852    }
853    *output.add(1) = 0;
854    output
855}
856
857static mut CRYPT_BUF: [u8; 128] = [0; 128];
858
859#[no_mangle]
860pub unsafe extern "C" fn crypt(key: *const c_char, setting: *const c_char) -> *mut c_char {
861    __crypt_r(key, setting, core::ptr::addr_of_mut!(CRYPT_BUF) as *mut crate::c_void)
862}
863
864#[no_mangle]
865pub unsafe extern "C" fn crypt_r(key: *const c_char, setting: *const c_char, data: *mut crate::c_void) -> *mut c_char {
866    __crypt_r(key, setting, data)
867}