Browse Source

Factorized and reworked fingerprint comparison code

doc_update_sequoia
Edouard Tisserant 5 years ago
parent
commit
72e7770638
3 changed files with 120 additions and 104 deletions
  1. +1
    -83
      src/message_api.c
  2. +98
    -21
      src/pEp_internal.h
  3. +21
    -0
      test/trustwords_test.cc

+ 1
- 83
src/message_api.c View File

@ -2244,88 +2244,6 @@ DYNAMIC_API PEP_color color_from_rating(PEP_rating rating)
return PEP_color_no_color;
}
static bool _is_valid_hex(const char* hexstr) {
if (!hexstr)
return false;
const char* curr = hexstr;
char currchar;
for (currchar = *curr; currchar != '\0'; currchar = *(++curr)) {
if ((currchar >= '0' && currchar <= '9') ||
(currchar >= 'a' && currchar <= 'f') ||
(currchar >= 'A' && currchar <= 'F'))
{
continue;
}
return false;
}
return true;
}
// Returns, in comparison: 1 if fpr1 > fpr2, 0 if equal, -1 if fpr1 < fpr2
static PEP_STATUS _compare_fprs(const char* fpr1, const char* fpr2, int* comparison) {
const int _FULL_FINGERPRINT_LENGTH = 40;
const int _ASCII_LOWERCASE_OFFSET = 32;
size_t fpr1_len = strlen(fpr1);
size_t fpr2_len = strlen(fpr2);
if (fpr1_len != _FULL_FINGERPRINT_LENGTH || fpr2_len != _FULL_FINGERPRINT_LENGTH)
return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
if (!_is_valid_hex(fpr1) || !_is_valid_hex(fpr2))
return PEP_ILLEGAL_VALUE;
const char* fpr1_curr = fpr1;
const char* fpr2_curr = fpr2;
char current;
// Advance past leading zeros.
for (current = *fpr1_curr; current != '0' && current != '\0'; current = *(++fpr1_curr), fpr1_len--);
for (current = *fpr2_curr; current != '0' && current != '\0'; current = *(++fpr2_curr), fpr2_len--);
if (fpr1_len == fpr2_len) {
char digit1;
char digit2;
while (fpr1_curr && *fpr1_curr != '\0') {
digit1 = *fpr1_curr++;
digit2 = *fpr2_curr++;
// Adjust for case-insensitive compare
if (digit1 >= 'a' && digit1 <= 'f')
digit1 -= _ASCII_LOWERCASE_OFFSET;
if (digit2 >= 'a' && digit2 <= 'f')
digit2 -= _ASCII_LOWERCASE_OFFSET;
// We take advantage of the fact that 'a'-'f' are larger
// integer values in the ASCII table than '0'-'9'.
// This allows us to compare digits directly.
if (digit1 > digit2) {
*comparison = 1;
return PEP_STATUS_OK;
} else if (digit1 < digit2) {
*comparison = -1;
return PEP_STATUS_OK;
}
// pointers already advanced above. Keep going.
}
*comparison = 0;
return PEP_STATUS_OK;
}
else if (fpr1_len > fpr2_len) {
*comparison = 1;
return PEP_STATUS_OK;
}
// Otherwise, fpr1_len < fpr2_len
*comparison = -1;
return PEP_STATUS_OK;
}
DYNAMIC_API PEP_STATUS get_trustwords(
PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
const char* lang, char **words, size_t *wsize, bool full
@ -2361,7 +2279,7 @@ DYNAMIC_API PEP_STATUS get_trustwords(
size_t second_wsize = 0;
int fpr_comparison = -255;
PEP_STATUS status = _compare_fprs(source1, source2, &fpr_comparison);
PEP_STATUS status = _compare_fprs(source1, strlen(source1), source2, strlen(source2), &fpr_comparison);
if (status != PEP_STATUS_OK)
return status;


+ 98
- 21
src/pEp_internal.h View File

@ -189,43 +189,120 @@ PEP_STATUS encrypt_only(
}
#endif
typedef enum _normalize_hex_rest_t {
accept_hex,
ignore_hex,
reject_hex
} normalize_hex_res_t;
static inline normalize_hex_res_t _normalize_hex(char *hex)
{
if (*hex >= '0' && *hex <= '9')
return accept_hex;
if (*hex >= 'A' && *hex <= 'F') {
*hex += 'a' - 'A';
return accept_hex;
}
if (*hex >= 'a' && *hex <= 'f')
return accept_hex;
if (*hex == ' ')
return ignore_hex;
return reject_hex;
}
// Space tolerant and case insensitive fingerprint string compare
static inline int _same_fpr(
static inline PEP_STATUS _compare_fprs(
const char* fpra,
size_t fpras,
const char* fprb,
size_t fprbs
)
size_t fprbs,
int* comparison)
{
size_t ai = 0;
size_t bi = 0;
do
size_t significant = 0;
int _comparison = 0;
const int _FULL_FINGERPRINT_LENGTH = 40;
// First compare every non-ignored chars until an end is reached
while(ai < fpras && bi < fprbs)
{
if(fpra[ai] == 0 || fprb[bi] == 0)
{
return 0;
}
else if(fpra[ai] == ' ')
char fprac = fpra[ai];
char fprbc = fprb[bi];
normalize_hex_res_t fprah = _normalize_hex(&fprac);
normalize_hex_res_t fprbh = _normalize_hex(&fprbc);
if(fprah == reject_hex || fprbh == reject_hex)
return PEP_ILLEGAL_VALUE;
if ( fprah == ignore_hex )
{
ai++;
}
else if(fprb[bi] == ' ')
else if ( fprbh == ignore_hex )
{
bi++;
}
else if(toupper(fpra[ai]) == toupper(fprb[bi]))
else
{
if(fprac != fprbc && _comparison == 0 )
{
_comparison = fprac > fprbc ? 1 : -1;
}
significant++;
ai++;
bi++;
}
else
{
return 0;
}
}
}
while(ai < fpras && bi < fprbs);
return ai == fpras && bi == fprbs;
// Bail out if we didn't got enough significnt chars
if (significant != _FULL_FINGERPRINT_LENGTH )
return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
// Then purge remaining chars, all must be ignored chars
while ( ai < fpras )
{
char fprac = fpra[ai];
normalize_hex_res_t fprah = _normalize_hex(&fprac);
if( fprah == reject_hex )
return PEP_ILLEGAL_VALUE;
if ( fprah != ignore_hex )
return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
ai++;
}
while ( bi < fprbs )
{
char fprbc = fprb[bi];
normalize_hex_res_t fprbh = _normalize_hex(&fprbc);
if( fprbh == reject_hex )
return PEP_ILLEGAL_VALUE;
if ( fprbh != ignore_hex )
return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
bi++;
}
*comparison = _comparison;
return PEP_STATUS_OK;
}
static inline int _same_fpr(
const char* fpra,
size_t fpras,
const char* fprb,
size_t fprbs
)
{
// illegal values are ignored, and considered not same.
int comparison = 1;
_compare_fprs(fpra, fpras, fprb, fprbs, &comparison);
return comparison == 0;
}

+ 21
- 0
test/trustwords_test.cc View File

@ -33,6 +33,12 @@ int main() {
"blargh",
"Krista Grothoff");
pEp_identity* identity2_with_spaces = new_identity(
"krista@kgrothoff.org",
" 62D4932086185C159 17B72D30571A FBCA 5493553 ",
"blargh",
"Krista Grothoff");
string fingerprint1 = identity1->fpr;
string fingerprint2 = identity2->fpr;
char* words1 = nullptr;
@ -58,6 +64,11 @@ int main() {
get_trustwords(session, identity1, identity2, "de", &full_wordlist, &wsize_full, false);
assert(full_wordlist);
cout << full_wordlist << "\n";
cout << "\nfinding German trustwords for " << identity1->address << " and " << identity2->address << "...\n";
get_trustwords(session, identity1, identity2_with_spaces, "de", &full_wordlist, &wsize_full, false);
assert(full_wordlist);
cout << full_wordlist << "\n";
pEp_free(words1);
@ -79,6 +90,11 @@ int main() {
assert(full_wordlist);
cout << full_wordlist << "\n";
cout << "\nfinding French trustwords for " << identity2->address << " and " << identity2->address << "...\n";
get_trustwords(session, identity2, identity2_with_spaces, "fr", &full_wordlist, &wsize_full, false);
assert(full_wordlist);
cout << full_wordlist << "\n";
pEp_free(words1);
words1 = nullptr;
pEp_free(full_wordlist);
@ -101,6 +117,11 @@ int main() {
assert(full_wordlist);
cout << full_wordlist << "\n";
cout << "\nfinding English trustwords for " << identity2->address << " and " << identity2->address << "...\n";
get_trustwords(session, identity2_with_spaces, identity1, "en", &full_wordlist, &wsize_full, true);
assert(full_wordlist);
cout << full_wordlist << "\n";
pEp_free(words1);
words1 = nullptr;
pEp_free(words2);


Loading…
Cancel
Save