diff --git a/src/wscutil.c b/src/wscutil.c index aa55f7e3..3060e418 100644 --- a/src/wscutil.c +++ b/src/wscutil.c @@ -2531,3 +2531,31 @@ bool wsc_pin_is_valid(const char *pin) return true; } + +/* Takes the first 7 characters of a PIN as input and computes a check digit */ +static char compute_check_digit(const char *pin) +{ + unsigned int accum = 0; + unsigned int digit; + + accum += 3 * ((pin[0] - '0') % 10); + accum += 1 * ((pin[1] - '0') % 10); + accum += 3 * ((pin[2] - '0') % 10); + accum += 1 * ((pin[3] - '0') % 10); + accum += 3 * ((pin[4] - '0') % 10); + accum += 1 * ((pin[5] - '0') % 10); + accum += 3 * ((pin[6] - '0') % 10); + + digit = (10 - (accum % 10)) % 10; + return '0' + digit; +} + +/* + * Validates the checksum digit and returns true if valid. Assumes that the + * input is an 8-byte PIN already validated by wsc_pin_is_valid() + */ +bool wsc_pin_is_checksum_valid(const char *pin) +{ + char digit = compute_check_digit(pin); + return pin[7] == digit; +} diff --git a/src/wscutil.h b/src/wscutil.h index 1d86c0b0..2764f0d9 100644 --- a/src/wscutil.h +++ b/src/wscutil.h @@ -639,3 +639,4 @@ struct wsc_session_key { bool wsc_kdf(const void *kdk, void *output, size_t size); bool wsc_pin_is_valid(const char *pin); +bool wsc_pin_is_checksum_valid(const char *pin);