package Config::ClawsMail::Password;
use strict;
use warnings;
use Config::ClawsMail::Password::Inline 'C';
use MIME::Base64;
use namespace::clean -except => [qw(decrypt_password)];
sub cleartext_password {
my ($password) = @_;
return decrypt_password(decode_base64($password));
}
1;
__DATA__
__C__
unsigned char crypt_cfb_iv[64];
int crypt_cfb_blocksize = 8; /* 8 for DES */
static void crypt_unpack(unsigned char *a) {
int i, j;
for (i = 7; i >= 0; --i)
for (j = 7; j >= 0; --j)
a[(i << 3) + j] = (a[i] & (0x80 >> j)) != 0;
}
static void crypt_cfb_xor(
unsigned char *to,
const unsigned char *from,
unsigned len) {
unsigned i;
unsigned j;
unsigned char c;
for (i = 0; i < len; i++) {
c = 0;
for (j = 0; j < 8; j++)
c = (c << 1) | *from++;
*to++ ^= c;
}
}
static void crypt_cfb_shift(
unsigned char *to,
const unsigned char *from,
unsigned len) {
unsigned i;
unsigned j;
unsigned k;
if (len < crypt_cfb_blocksize) {
i = len * 8;
j = crypt_cfb_blocksize * 8;
for (k = i; k < j; k++) {
to[0] = to[i];
++to;
}
}
for (i = 0; i < len; i++) {
j = *from++;
for (k = 0x80; k; k >>= 1)
*to++ = ((j & k) != 0);
}
}
static void crypt_cfb_buf(
const char key[8],
unsigned char *buf,
unsigned len,
unsigned chunksize,
int decrypt) {
unsigned char temp[64];
memcpy(temp, key, 8);
crypt_unpack(temp);
setkey((const char *) temp);
memset(temp, 0, sizeof(temp));
memset(crypt_cfb_iv, 0, sizeof(crypt_cfb_iv));
if (chunksize > crypt_cfb_blocksize)
chunksize = crypt_cfb_blocksize;
while (len) {
memcpy(temp, crypt_cfb_iv, sizeof(temp));
encrypt((char *) temp, 0);
if (chunksize > len)
chunksize = len;
if (decrypt)
crypt_cfb_shift(crypt_cfb_iv, buf, chunksize);
crypt_cfb_xor((unsigned char *) buf, temp, chunksize);
if (!decrypt)
crypt_cfb_shift(crypt_cfb_iv, buf, chunksize);
len -= chunksize;
buf += chunksize;
}
}
SV* decrypt_password(SV* password) {
size_t len = sv_len(password);
char *tmp = (char*)malloc(len);
memcpy(tmp,SvPVbyte(password,len),len);
crypt_cfb_buf(PASSCRYPT_KEY, tmp, len, 1, 1 );
return newSVpvn(tmp,len);
}