- added untested function to decrypt sm
- function cipher now always disables automatic padding git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@52 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
201
ccid/sm.c
201
ccid/sm.c
@@ -24,7 +24,7 @@ static const struct sc_asn1_entry c_sm_rapdu[] = {
|
|||||||
{ NULL, 0, 0, 0, NULL, NULL }
|
{ NULL, 0, 0, 0, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
BUF_MEM *add_padding(const struct sm_ctx *ctx, const char *data, size_t datalen)
|
BUF_MEM * add_padding(const struct sm_ctx *ctx, const char *data, size_t datalen)
|
||||||
{
|
{
|
||||||
BUF_MEM *tmp = BUF_MEM_create_init(data, datalen);
|
BUF_MEM *tmp = BUF_MEM_create_init(data, datalen);
|
||||||
BUF_MEM *padded = NULL;
|
BUF_MEM *padded = NULL;
|
||||||
@@ -48,6 +48,35 @@ BUF_MEM *add_padding(const struct sm_ctx *ctx, const char *data, size_t datalen)
|
|||||||
return padded;
|
return padded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int no_padding(u8 padding_indicator, const char *data, size_t datalen,
|
||||||
|
size_t *raw_len)
|
||||||
|
{
|
||||||
|
if (!datalen || !data)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
switch (padding_indicator) {
|
||||||
|
case SM_NO_PADDING:
|
||||||
|
len = datalen;
|
||||||
|
break;
|
||||||
|
case SM_ISO_PADDING:
|
||||||
|
for (len = datalen;
|
||||||
|
len && (data[len-1] == 0);
|
||||||
|
len--) { };
|
||||||
|
|
||||||
|
if (data[len-1] != 0x80)
|
||||||
|
return SC_ERROR_INVALID_DATA;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
*raw_len = len;
|
||||||
|
|
||||||
|
return SC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
u8 * format_le(size_t le_len, size_t le, struct sc_asn1_entry *le_entry)
|
u8 * format_le(size_t le_len, size_t le, struct sc_asn1_entry *le_entry)
|
||||||
{
|
{
|
||||||
u8 * lebuf = malloc(le_len);
|
u8 * lebuf = malloc(le_len);
|
||||||
@@ -91,9 +120,10 @@ BUF_MEM * prefix_buf(u8 prefix, BUF_MEM *buf)
|
|||||||
BUF_MEM * format_data(const struct sm_ctx *ctx, const u8 *data, size_t datalen,
|
BUF_MEM * format_data(const struct sm_ctx *ctx, const u8 *data, size_t datalen,
|
||||||
struct sc_asn1_entry *formatted_encrypted_data_entry)
|
struct sc_asn1_entry *formatted_encrypted_data_entry)
|
||||||
{
|
{
|
||||||
|
|
||||||
BUF_MEM *pad_data = add_padding(ctx, (char *) data, datalen);
|
BUF_MEM *pad_data = add_padding(ctx, (char *) data, datalen);
|
||||||
BUF_MEM *enc_data = cipher(ctx->cipher_ctx, ctx->cipher,
|
BUF_MEM *enc_data = cipher(ctx->cipher_ctx, ctx->cipher,
|
||||||
ctx->cipher_engine, ctx->key_enc, ctx->iv, 1, pad_data, 1);
|
ctx->cipher_engine, ctx->key_enc, ctx->iv, 1, pad_data);
|
||||||
|
|
||||||
if (pad_data) {
|
if (pad_data) {
|
||||||
OPENSSL_cleanse(pad_data->data, pad_data->max);
|
OPENSSL_cleanse(pad_data->data, pad_data->max);
|
||||||
@@ -113,15 +143,25 @@ BUF_MEM * format_data(const struct sm_ctx *ctx, const u8 *data, size_t datalen,
|
|||||||
return indicator_encdata;
|
return indicator_encdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sc_apdu_t *apdu,
|
BUF_MEM * format_head(const struct sm_ctx *ctx, const sc_apdu_t *apdu)
|
||||||
sc_apdu_t *sm_apdu)
|
{
|
||||||
|
char head[4];
|
||||||
|
|
||||||
|
head[0] = apdu->cla;
|
||||||
|
head[1] = apdu->ins;
|
||||||
|
head[2] = apdu->p1;
|
||||||
|
head[3] = apdu->p2;
|
||||||
|
return add_padding(ctx, head, sizeof head);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
|
||||||
|
const sc_apdu_t *apdu, sc_apdu_t *sm_apdu)
|
||||||
{
|
{
|
||||||
struct sc_asn1_entry sm_capdu[4];
|
struct sc_asn1_entry sm_capdu[4];
|
||||||
u8 *le = NULL;
|
u8 *le = NULL;
|
||||||
size_t oldlen;
|
size_t oldlen;
|
||||||
BUF_MEM *formatted_data = NULL, *sm_data = NULL,
|
BUF_MEM *fdata = NULL, *sm_data = NULL,
|
||||||
*mac_data = NULL, *mac = NULL, *tmp = NULL;
|
*mac_data = NULL, *mac = NULL, *tmp = NULL;
|
||||||
char head[4];
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!apdu || !ctx || !card || !card->slot || !sm_apdu) {
|
if (!apdu || !ctx || !card || !card->slot || !sm_apdu) {
|
||||||
@@ -129,22 +169,15 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sc_apdu_t *apdu,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sc_copy_asn1_entry(c_sm_capdu, sm_capdu);
|
sc_copy_asn1_entry(c_sm_capdu, sm_capdu);
|
||||||
|
|
||||||
head[0] = apdu->cla;
|
mac_data = format_head(ctx, apdu);
|
||||||
head[1] = apdu->ins;
|
|
||||||
head[2] = apdu->p1;
|
|
||||||
head[3] = apdu->p2;
|
|
||||||
mac_data = add_padding(ctx, head, sizeof head);
|
|
||||||
if (!mac_data) {
|
if (!mac_data) {
|
||||||
r = SC_ERROR_WRONG_PADDING;
|
r = SC_ERROR_WRONG_PADDING;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get le and data depending on the case of the unsecure command */
|
||||||
/* get asn1 encoding of le and padding indicator depending on the case of
|
|
||||||
* the unsecure command */
|
|
||||||
switch (apdu->cse) {
|
switch (apdu->cse) {
|
||||||
case SC_APDU_CASE_1:
|
case SC_APDU_CASE_1:
|
||||||
break;
|
break;
|
||||||
@@ -174,9 +207,9 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sc_apdu_t *apdu,
|
|||||||
break;
|
break;
|
||||||
case SC_APDU_CASE_3_SHORT:
|
case SC_APDU_CASE_3_SHORT:
|
||||||
case SC_APDU_CASE_3_EXT:
|
case SC_APDU_CASE_3_EXT:
|
||||||
formatted_data = format_data(ctx, apdu->data, apdu->datalen,
|
fdata = format_data(ctx, apdu->data, apdu->datalen,
|
||||||
sm_capdu + 0);
|
sm_capdu + 0);
|
||||||
if (!formatted_data) {
|
if (!fdata) {
|
||||||
r = SC_ERROR_OUT_OF_MEMORY;
|
r = SC_ERROR_OUT_OF_MEMORY;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@@ -191,9 +224,9 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sc_apdu_t *apdu,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatted_data = format_data(ctx, apdu->data, apdu->datalen,
|
fdata = format_data(ctx, apdu->data, apdu->datalen,
|
||||||
sm_capdu + 0);
|
sm_capdu + 0);
|
||||||
if (!formatted_data) {
|
if (!fdata) {
|
||||||
r = SC_ERROR_OUT_OF_MEMORY;
|
r = SC_ERROR_OUT_OF_MEMORY;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@@ -213,9 +246,9 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sc_apdu_t *apdu,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatted_data = format_data(ctx, apdu->data, apdu->datalen,
|
fdata = format_data(ctx, apdu->data, apdu->datalen,
|
||||||
sm_capdu + 0);
|
sm_capdu + 0);
|
||||||
if (!formatted_data) {
|
if (!fdata) {
|
||||||
r = SC_ERROR_OUT_OF_MEMORY;
|
r = SC_ERROR_OUT_OF_MEMORY;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@@ -243,7 +276,7 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sc_apdu_t *apdu,
|
|||||||
BUF_MEM_free(mac_data);
|
BUF_MEM_free(mac_data);
|
||||||
mac_data = hash(ctx->md, ctx->md_ctx, ctx->md_engine, tmp);
|
mac_data = hash(ctx->md, ctx->md_ctx, ctx->md_engine, tmp);
|
||||||
mac = cipher(ctx->cipher_ctx, ctx->cipher, ctx->cipher_engine,
|
mac = cipher(ctx->cipher_ctx, ctx->cipher, ctx->cipher_engine,
|
||||||
ctx->key_mac, ctx->iv, 1, mac_data, 1);
|
ctx->key_mac, ctx->iv, 1, mac_data);
|
||||||
if (!mac) {
|
if (!mac) {
|
||||||
r = SC_ERROR_INTERNAL;
|
r = SC_ERROR_INTERNAL;
|
||||||
goto err;
|
goto err;
|
||||||
@@ -262,19 +295,21 @@ int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sc_apdu_t *apdu,
|
|||||||
r = sc_asn1_encode(card->ctx, sm_capdu, (u8 **) &sm_data->data, &sm_data->length);
|
r = sc_asn1_encode(card->ctx, sm_capdu, (u8 **) &sm_data->data, &sm_data->length);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto err;
|
goto err;
|
||||||
memset(sm_apdu, 0, sizeof *sm_apdu);
|
memcpy(sm_apdu, apdu, sizeof *sm_apdu);
|
||||||
sm_apdu->cla = apdu->cla;
|
|
||||||
sm_apdu->ins = apdu->ins;
|
|
||||||
sm_apdu->p1 = apdu->p1;
|
|
||||||
sm_apdu->p2 = apdu->p2;
|
|
||||||
sm_apdu->data = (u8 *) sm_data->data;
|
sm_apdu->data = (u8 *) sm_data->data;
|
||||||
sm_apdu->lc = sm_data->length;
|
sm_apdu->lc = sm_data->length;
|
||||||
sm_apdu->le = 0;
|
sm_apdu->le = 0;
|
||||||
sm_apdu->cse = SC_APDU_CASE_4;
|
sm_apdu->cse = SC_APDU_CASE_4;
|
||||||
|
|
||||||
|
|
||||||
|
/* BUF_MEM_free must not free sm_data->data */
|
||||||
|
sm_data->data = NULL;
|
||||||
|
sm_data->length = 0;
|
||||||
|
sm_data->max = 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (formatted_data) {
|
if (fdata) {
|
||||||
BUF_MEM_free(formatted_data);
|
BUF_MEM_free(fdata);
|
||||||
}
|
}
|
||||||
if (tmp) {
|
if (tmp) {
|
||||||
BUF_MEM_free(tmp);
|
BUF_MEM_free(tmp);
|
||||||
@@ -285,9 +320,117 @@ err:
|
|||||||
if (mac) {
|
if (mac) {
|
||||||
BUF_MEM_free(mac);
|
BUF_MEM_free(mac);
|
||||||
}
|
}
|
||||||
|
if (sm_data) {
|
||||||
|
BUF_MEM_free(sm_data);
|
||||||
|
}
|
||||||
if (le) {
|
if (le) {
|
||||||
free(le);
|
free(le);
|
||||||
}
|
}
|
||||||
|
|
||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r);
|
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sm_decrypt(const struct sm_ctx *ctx, sc_card_t *card,
|
||||||
|
const sc_apdu_t *sm_apdu, sc_apdu_t *apdu)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct sc_asn1_entry sm_rapdu[4];
|
||||||
|
u8 sw[2], mac[EVP_CIPHER_block_size(ctx->cipher)], fdata[1024];
|
||||||
|
size_t sw_len = sizeof sw, mac_len = sizeof mac, fdata_len = sizeof fdata,
|
||||||
|
buf_len, oldlen;
|
||||||
|
const u8 *buf;
|
||||||
|
BUF_MEM *mac_data = NULL, *tmp = NULL, *my_mac = NULL, *data = NULL,
|
||||||
|
enc_data;
|
||||||
|
|
||||||
|
sc_copy_asn1_entry(c_sm_rapdu, sm_rapdu);
|
||||||
|
sc_format_asn1_entry(sm_rapdu + 0, fdata, &fdata_len, 0);
|
||||||
|
sc_format_asn1_entry(sm_rapdu + 1, sw, &sw_len, 0);
|
||||||
|
sc_format_asn1_entry(sm_rapdu + 2, mac, &mac_len, 0);
|
||||||
|
|
||||||
|
r = sc_asn1_decode(card->ctx, sm_rapdu, apdu->resp, apdu->resplen,
|
||||||
|
&buf, &buf_len);
|
||||||
|
if (r < 0)
|
||||||
|
goto err;
|
||||||
|
if (buf_len > 0) {
|
||||||
|
r = SC_ERROR_TOO_MANY_OBJECTS;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (sm_rapdu[0].flags & SC_ASN1_PRESENT) {
|
||||||
|
if (ctx->padding_indicator != fdata[0]) {
|
||||||
|
r = SC_ERROR_DECRYPT_FAILED;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
enc_data.data = (char *) fdata + 1;
|
||||||
|
enc_data.length = fdata_len - 1;
|
||||||
|
enc_data.max = enc_data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mac_data = format_head(ctx, sm_apdu);
|
||||||
|
|
||||||
|
tmp = BUF_MEM_new();
|
||||||
|
if (!tmp) {
|
||||||
|
r = SC_ERROR_OUT_OF_MEMORY;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
sc_format_asn1_entry(sm_rapdu + 2, NULL, NULL, 0);
|
||||||
|
r = sc_asn1_encode(card->ctx, sm_rapdu, (u8 **) &tmp->data, &tmp->length);
|
||||||
|
if (r < 0)
|
||||||
|
goto err;
|
||||||
|
oldlen = mac_data->length;
|
||||||
|
BUF_MEM_grow(mac_data, oldlen + tmp->length);
|
||||||
|
memcpy(mac_data->data + oldlen, tmp->data, tmp->length);
|
||||||
|
free(tmp->data);
|
||||||
|
tmp = add_padding(ctx, mac_data->data, mac_data->length);
|
||||||
|
BUF_MEM_free(mac_data);
|
||||||
|
mac_data = hash(ctx->md, ctx->md_ctx, ctx->md_engine, tmp);
|
||||||
|
my_mac = cipher(ctx->cipher_ctx, ctx->cipher, ctx->cipher_engine,
|
||||||
|
ctx->key_mac, ctx->iv, 1, mac_data);
|
||||||
|
if (!my_mac) {
|
||||||
|
r = SC_ERROR_INTERNAL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_mac->length != mac_len ||
|
||||||
|
memcmp(my_mac->data, mac, mac_len) != 0) {
|
||||||
|
r = SC_ERROR_DECRYPT_FAILED;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
data = cipher(ctx->cipher_ctx, ctx->cipher, ctx->cipher_engine,
|
||||||
|
ctx->key_enc, ctx->iv, 0, &enc_data);
|
||||||
|
r = no_padding(ctx->padding_indicator, data->data, data->length,
|
||||||
|
&data->length);
|
||||||
|
if (r < 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
|
||||||
|
memcpy(apdu, sm_apdu, sizeof *apdu);
|
||||||
|
apdu->resp = (u8 *) data->data;
|
||||||
|
apdu->resplen = data->length;
|
||||||
|
|
||||||
|
|
||||||
|
/* BUF_MEM_free must not free data->data */
|
||||||
|
data->data = NULL;
|
||||||
|
data->length = 0;
|
||||||
|
data->max = 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (tmp) {
|
||||||
|
BUF_MEM_free(tmp);
|
||||||
|
}
|
||||||
|
if (mac_data) {
|
||||||
|
BUF_MEM_free(mac_data);
|
||||||
|
}
|
||||||
|
if (my_mac) {
|
||||||
|
BUF_MEM_free(my_mac);
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
BUF_MEM_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r);
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,6 +20,3 @@ struct sm_ctx {
|
|||||||
EVP_MD_CTX * md_ctx;
|
EVP_MD_CTX * md_ctx;
|
||||||
ENGINE *md_engine;
|
ENGINE *md_engine;
|
||||||
};
|
};
|
||||||
|
|
||||||
int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sc_apdu_t *apdu,
|
|
||||||
sc_apdu_t *sm_apdu);
|
|
||||||
|
|||||||
17
ccid/utils.c
17
ccid/utils.c
@@ -56,8 +56,7 @@ err:
|
|||||||
|
|
||||||
BUF_MEM *
|
BUF_MEM *
|
||||||
cipher(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
|
cipher(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
|
||||||
unsigned char *key, unsigned char *iv, int enc, const BUF_MEM * in,
|
unsigned char *key, unsigned char *iv, int enc, const BUF_MEM * in)
|
||||||
int init)
|
|
||||||
{
|
{
|
||||||
BUF_MEM * out = NULL;
|
BUF_MEM * out = NULL;
|
||||||
EVP_CIPHER_CTX * tmp_ctx = NULL;
|
EVP_CIPHER_CTX * tmp_ctx = NULL;
|
||||||
@@ -75,7 +74,7 @@ cipher(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
|
|||||||
EVP_CIPHER_CTX_init(tmp_ctx);
|
EVP_CIPHER_CTX_init(tmp_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->flags & EVP_CIPH_NO_PADDING) {
|
if (tmp_ctx->flags & EVP_CIPH_NO_PADDING) {
|
||||||
i = in->length;
|
i = in->length;
|
||||||
if (in->length % EVP_CIPHER_block_size(type) != 0) {
|
if (in->length % EVP_CIPHER_block_size(type) != 0) {
|
||||||
printf("Input length is not a multiple of block length\n");
|
printf("Input length is not a multiple of block length\n");
|
||||||
@@ -89,20 +88,20 @@ cipher(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
|
|||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
/* get cipher */
|
/* get cipher */
|
||||||
if (ctx && init)
|
if (!EVP_CipherInit_ex(tmp_ctx, type, impl, key, iv, enc)
|
||||||
if (!EVP_CipherInit_ex(tmp_ctx, type, impl, key, iv, enc))
|
|| !EVP_CIPHER_CTX_set_padding(tmp_ctx, 0))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (!EVP_CipherUpdate(ctx, (unsigned char *) out->data, &i,
|
if (!EVP_CipherUpdate(tmp_ctx, (unsigned char *) out->data, &i,
|
||||||
(unsigned char *) in->data, in->length))
|
(unsigned char *) in->data, in->length))
|
||||||
goto err;
|
goto err;
|
||||||
out->length = i;
|
out->length = i;
|
||||||
|
|
||||||
if (!EVP_CipherFinal_ex(ctx, (unsigned char *) (out->data + out->length),
|
if (!EVP_CipherFinal_ex(tmp_ctx, (unsigned char *) (out->data + out->length),
|
||||||
&i))
|
&i))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (!(ctx->flags & EVP_CIPH_NO_PADDING))
|
if (!(tmp_ctx->flags & EVP_CIPH_NO_PADDING))
|
||||||
out->length += i;
|
out->length += i;
|
||||||
|
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
|
|||||||
@@ -35,14 +35,14 @@ hash(const EVP_MD * md, EVP_MD_CTX * ctx, ENGINE * impl, const BUF_MEM * in);
|
|||||||
* @param iv only evaluated if init is 1. (optional)
|
* @param iv only evaluated if init is 1. (optional)
|
||||||
* @param enc only evaluated if init is 1.
|
* @param enc only evaluated if init is 1.
|
||||||
* @param in
|
* @param in
|
||||||
* @param init whether to initialize (1) the given ctx or not (0).
|
|
||||||
*
|
*
|
||||||
* @return cipher of in or NULL if an error occurred
|
* @return cipher of in or NULL if an error occurred
|
||||||
|
*
|
||||||
|
* @note automatic padding is disabled
|
||||||
*/
|
*/
|
||||||
BUF_MEM *
|
BUF_MEM *
|
||||||
cipher(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
|
cipher(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
|
||||||
unsigned char *key, unsigned char *iv, int enc, const BUF_MEM * in,
|
unsigned char *key, unsigned char *iv, int enc, const BUF_MEM * in);
|
||||||
const int init);
|
|
||||||
/**
|
/**
|
||||||
* @brief Padds a buffer using ISO/IEC 9797-1 padding method 2.
|
* @brief Padds a buffer using ISO/IEC 9797-1 padding method 2.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user