188 lines
5.7 KiB
C++
188 lines
5.7 KiB
C++
MODULE = CryptX PACKAGE = Crypt::Cipher
|
|
|
|
PROTOTYPES: DISABLE
|
|
|
|
Crypt::Cipher
|
|
new(char * class, ...)
|
|
CODE:
|
|
{
|
|
STRLEN key_len;
|
|
unsigned char *key_data = NULL;
|
|
SV *key;
|
|
char *cipher_name;
|
|
int rv, id, rounds = 0, idx;
|
|
|
|
/* we need to handle:
|
|
Crypt::Cipher->new('AES');
|
|
Crypt::Cipher::AES->new();
|
|
*/
|
|
idx = strcmp("Crypt::Cipher", class) == 0 ? 1 : 0;
|
|
if (idx + 1 > items) croak("FATAL: missing argument");
|
|
cipher_name = SvPVX(ST(idx));
|
|
key = ST(idx + 1);
|
|
if (idx + 3 <= items) rounds = (int)SvIV(ST(idx + 2));
|
|
|
|
if (!SvPOK (key)) croak("FATAL: key must be string scalar");
|
|
key_data = (unsigned char *)SvPVbyte(key, key_len);
|
|
|
|
id = _find_cipher(cipher_name);
|
|
if (id == -1) croak("FATAL: find_cipfer failed for '%s'", cipher_name);
|
|
|
|
Newz(0, RETVAL, 1, struct cipher_struct);
|
|
if (!RETVAL) croak("FATAL: Newz failed");
|
|
|
|
RETVAL->desc = &cipher_descriptor[id];
|
|
rv = RETVAL->desc->setup(key_data, (int)key_len, rounds, &RETVAL->skey);
|
|
if (rv != CRYPT_OK) {
|
|
Safefree(RETVAL);
|
|
croak("FATAL: cipher setup failed: %s", error_to_string(rv));
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
DESTROY(Crypt::Cipher self)
|
|
CODE:
|
|
Safefree(self);
|
|
|
|
SV *
|
|
encrypt(Crypt::Cipher self, SV * data)
|
|
CODE:
|
|
{
|
|
int rv;
|
|
STRLEN len;
|
|
void *plaintext = SvPVbyte(data, len);
|
|
|
|
if (len == 0) {
|
|
RETVAL = newSVpvn("", 0);
|
|
}
|
|
else if (len == (STRLEN)self->desc->block_length) {
|
|
RETVAL = NEWSV(0, len); /* avoid zero! */
|
|
SvPOK_only(RETVAL);
|
|
SvCUR_set(RETVAL, len);
|
|
rv = self->desc->ecb_encrypt((unsigned char *)plaintext, (unsigned char *)SvPVX(RETVAL), &self->skey);
|
|
if (rv!=CRYPT_OK) {
|
|
SvREFCNT_dec(RETVAL);
|
|
croak("FATAL: encrypt failed: %s", error_to_string(rv));
|
|
}
|
|
}
|
|
else {
|
|
croak ("FATAL: input size not equal to blocksize (%d)", self->desc->block_length);
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
decrypt(Crypt::Cipher self, SV * data)
|
|
CODE:
|
|
{
|
|
int rv;
|
|
STRLEN len;
|
|
void *ciphertext = SvPVbyte(data, len);
|
|
|
|
if (len == 0) {
|
|
RETVAL = newSVpvn("", 0);
|
|
}
|
|
else if (len == (STRLEN)self->desc->block_length) {
|
|
RETVAL = NEWSV(0, len); /* avoid zero! */
|
|
SvPOK_only(RETVAL);
|
|
SvCUR_set(RETVAL, len);
|
|
rv = self->desc->ecb_decrypt((unsigned char *)ciphertext, (unsigned char *)SvPVX(RETVAL), &self->skey);
|
|
if (rv!=CRYPT_OK) {
|
|
SvREFCNT_dec(RETVAL);
|
|
croak("FATAL: decrypt failed: %s", error_to_string(rv));
|
|
}
|
|
}
|
|
else {
|
|
croak ("FATAL: input size not equal to blocksize (%d)", self->desc->block_length);
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
blocksize(SV * param, char * extra = NULL)
|
|
CODE:
|
|
{
|
|
if (sv_isobject(param) && sv_derived_from(param, "Crypt::Cipher")) {
|
|
IV tmp = SvIV((SV*)SvRV(param));
|
|
Crypt__Cipher obj = INT2PTR(Crypt__Cipher, tmp);
|
|
RETVAL = obj->desc->block_length;
|
|
}
|
|
else {
|
|
char *name = SvPOK(param) && strcmp(SvPVX(param), "Crypt::Cipher") ? SvPVX(param) : extra;
|
|
int rv, id = _find_cipher(name);
|
|
if (id == -1) croak("FATAL: find_cipher failed for '%s'", name);
|
|
rv = cipher_descriptor[id].block_length;
|
|
if (!rv) croak("FATAL: invalid block_length for '%s'", name);
|
|
RETVAL = rv;
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
max_keysize(SV * param, char * extra = NULL)
|
|
CODE:
|
|
{
|
|
if (sv_isobject(param) && sv_derived_from(param, "Crypt::Cipher")) {
|
|
IV tmp = SvIV((SV*)SvRV(param));
|
|
Crypt__Cipher obj = INT2PTR(Crypt__Cipher, tmp);
|
|
RETVAL = obj->desc->max_key_length;
|
|
}
|
|
else {
|
|
char *name = SvPOK(param) && strcmp(SvPVX(param), "Crypt::Cipher") ? SvPVX(param) : extra;
|
|
int rv, id = _find_cipher(name);
|
|
if (id == -1) croak("FATAL: find_cipher failed for '%s'", name);
|
|
rv = cipher_descriptor[id].max_key_length;
|
|
if (!rv) croak("FATAL: invalid max_key_length for '%s'", name);
|
|
RETVAL = rv;
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
min_keysize(SV * param, char * extra = NULL)
|
|
CODE:
|
|
{
|
|
if (sv_isobject(param) && sv_derived_from(param, "Crypt::Cipher")) {
|
|
IV tmp = SvIV((SV*)SvRV(param));
|
|
Crypt__Cipher obj = INT2PTR(Crypt__Cipher, tmp);
|
|
RETVAL = obj->desc->min_key_length;
|
|
}
|
|
else {
|
|
char *name = SvPOK(param) && strcmp(SvPVX(param), "Crypt::Cipher") ? SvPVX(param) : extra;
|
|
int rv, id = _find_cipher(name);
|
|
if (id == -1) croak("FATAL: find_cipher failed for '%s'", name);
|
|
rv = cipher_descriptor[id].min_key_length;
|
|
if (!rv) croak("FATAL: invalid min_key_length for '%s'", name);
|
|
RETVAL = rv;
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
default_rounds(SV * param, char * extra = NULL)
|
|
CODE:
|
|
{
|
|
if (sv_isobject(param) && sv_derived_from(param, "Crypt::Cipher")) {
|
|
IV tmp = SvIV((SV*)SvRV(param));
|
|
Crypt__Cipher obj = INT2PTR(Crypt__Cipher, tmp);
|
|
RETVAL = obj->desc->default_rounds;
|
|
}
|
|
else {
|
|
char *name = SvPOK(param) && strcmp(SvPVX(param), "Crypt::Cipher") ? SvPVX(param) : extra;
|
|
int rv, id = _find_cipher(name);
|
|
if (id == -1) croak("FATAL: find_cipher failed for '%s'", name);
|
|
rv = cipher_descriptor[id].default_rounds;
|
|
if (!rv) XSRETURN_UNDEF;
|
|
RETVAL = rv;
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|