optimize bin/hex low parsing level functions (#1646)

* optimize sc_hex_to_bin

* optimize sc_bin_to_hex

* added documentation

closes https://github.com/OpenSC/OpenSC/pull/1643

thanks to carblue <ka6613-496@online.de>
This commit is contained in:
Frank Morgner 2019-04-04 12:52:08 +02:00 committed by GitHub
parent 0abe9d11c7
commit fd20ffe608
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 57 deletions

View File

@ -1379,6 +1379,25 @@ const sc_path_t *sc_get_mf_path(void);
/********************************************************************/
int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen);
/**
* Converts an u8 array to a string representing the input as hexadecimal,
* human-readable/printable form. It's the inverse function of sc_hex_to_bin.
*
* @param in The u8 array input to be interpreted, may be NULL iff in_len==0
* @param in_len Less or equal to the amount of bytes available from in
* @param out output buffer offered for the string representation, *MUST NOT*
* be NULL and *MUST* be sufficiently sized, see out_len
* @param out_len *MUST* be at least 1 and state the maximum of bytes available
* within out to be written, including the \0 termination byte
* that will be written unconditionally
* @param separator The character to be used to separate the u8 string
* representations. `0` will suppress separation.
*
* Example: input [0x3f], in_len=1, requiring an out_len>=3, will write to out:
* [0x33, 0x66, 0x00] which reads as "3f"
* Example: input [0x3f, 0x01], in_len=2, separator=':', req. an out_len>=6,
* writes to out: [0x33, 0x66, 0x3A, 0x30, 0x31, 0x00] which reads as "3f:01"
*/
int sc_bin_to_hex(const u8 *, size_t, char *, size_t, int separator);
size_t sc_right_trim(u8 *buf, size_t len);
scconf_block *sc_get_conf_block(sc_context_t *ctx, const char *name1, const char *name2, int priority);

View File

@ -63,77 +63,90 @@ const char *sc_get_version(void)
int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen)
{
int err = SC_SUCCESS;
size_t left, count = 0, in_len;
const char *sc_hex_to_bin_separators = " :";
if (in == NULL || out == NULL || outlen == NULL) {
return SC_ERROR_INVALID_ARGUMENTS;
}
left = *outlen;
in_len = strlen(in);
while (*in != '\0') {
int byte = 0, nybbles = 2;
while (nybbles-- && *in && *in != ':' && *in != ' ') {
char c;
byte <<= 4;
c = *in++;
if ('0' <= c && c <= '9')
c -= '0';
else
if ('a' <= c && c <= 'f')
c = c - 'a' + 10;
else
if ('A' <= c && c <= 'F')
c = c - 'A' + 10;
else {
err = SC_ERROR_INVALID_ARGUMENTS;
goto out;
}
byte |= c;
int byte_needs_nibble = 0;
int r = SC_SUCCESS;
size_t left = *outlen;
u8 byte = 0;
while (*in != '\0' && 0 != left) {
char c = *in++;
u8 nibble;
if ('0' <= c && c <= '9')
nibble = c - '0';
else if ('a' <= c && c <= 'f')
nibble = c - 'a' + 10;
else if ('A' <= c && c <= 'F')
nibble = c - 'A' + 10;
else {
if (strchr(sc_hex_to_bin_separators, (int) c))
continue;
r = SC_ERROR_INVALID_ARGUMENTS;
goto err;
}
/* Detect premature end of string before byte is complete */
if (in_len > 1 && *in == '\0' && nybbles >= 0) {
err = SC_ERROR_INVALID_ARGUMENTS;
break;
if (byte_needs_nibble) {
byte |= nibble;
*out++ = (u8) byte;
left--;
byte_needs_nibble = 0;
} else {
byte = nibble << 4;
byte_needs_nibble = 1;
}
if (*in == ':' || *in == ' ')
in++;
if (left <= 0) {
err = SC_ERROR_BUFFER_TOO_SMALL;
break;
}
out[count++] = (u8) byte;
left--;
}
out:
*outlen = count;
return err;
/* for ease of implementation we only accept completely hexed bytes. */
if (byte_needs_nibble) {
r = SC_ERROR_INVALID_ARGUMENTS;
goto err;
}
/* skip all trailing separators to see if we missed something */
while (*in != '\0') {
if (NULL == strchr(sc_hex_to_bin_separators, (int) *in))
break;
in++;
}
if (*in != '\0') {
r = SC_ERROR_BUFFER_TOO_SMALL;
goto err;
}
err:
*outlen -= left;
return r;
}
int sc_bin_to_hex(const u8 *in, size_t in_len, char *out, size_t out_len,
int in_sep)
int in_sep)
{
unsigned int n, sep_len;
char *pos, *end, sep;
sep = (char)in_sep;
sep_len = sep > 0 ? 1 : 0;
pos = out;
end = out + out_len;
for (n = 0; n < in_len; n++) {
if (pos + 3 + sep_len >= end)
return SC_ERROR_BUFFER_TOO_SMALL;
if (n && sep_len)
*pos++ = sep;
sprintf(pos, "%02x", in[n]);
pos += 2;
if (in == NULL || out == NULL) {
return SC_ERROR_INVALID_ARGUMENTS;
}
*pos = '\0';
if (in_sep > 0) {
if (out_len < in_len*3 || out_len < 1)
return SC_ERROR_BUFFER_TOO_SMALL;
} else {
if (out_len < in_len*2 + 1)
return SC_ERROR_BUFFER_TOO_SMALL;
}
const char hex[] = "0123456789abcdef";
while (in_len) {
unsigned char value = *in++;
*out++ = hex[(value >> 4) & 0xF];
*out++ = hex[ value & 0xF];
in_len--;
if (in_len && in_sep > 0)
*out++ = (char)in_sep;
}
*out = '\0';
return SC_SUCCESS;
}