[perl FKO] add HMAC support along with test suite HMAC verification (closes #16)
authorMichael Rash <mbr@cipherdyne.org>
Fri, 22 Mar 2013 01:55:18 +0000 (21:55 -0400)
committerMichael Rash <mbr@cipherdyne.org>
Fri, 22 Mar 2013 01:55:18 +0000 (21:55 -0400)
perl/FKO/FKO.xs
perl/FKO/lib/FKO.pm
test/test-fwknop.pl
test/tests/perl_FKO_module.pl

index 9b1654d..7549a6e 100644 (file)
@@ -190,6 +190,16 @@ _set_hmac_type(ctx, hmac_type)
     RETVAL
 
 int
+_get_hmac_type(ctx, hmac_type)
+    INPUT:
+    fko_ctx_t ctx;
+    short    hmac_type;
+    CODE:
+    RETVAL = fko_get_spa_hmac_type(ctx, hmac_type);
+    OUTPUT:
+    RETVAL
+
+int
 _set_rand_value(ctx, rand_val)
     INPUT:
     fko_ctx_t ctx;
@@ -378,6 +388,17 @@ _get_spa_digest(ctx, val)
     RETVAL
 
 int
+_get_spa_hmac(ctx, val)
+    INPUT:
+    fko_ctx_t ctx;
+    char *val;
+    CODE:
+    RETVAL = fko_get_hmac_data(ctx, &val);
+    OUTPUT:
+    val
+    RETVAL
+
+int
 _set_spa_data(ctx, spa_data)
     INPUT:
     fko_ctx_t ctx;
@@ -607,6 +628,28 @@ _decrypt_spa_data(ctx, dec_key, dec_key_len)
     RETVAL
 
 int
+_verify_hmac(ctx, hmac_key, hmac_key_len)
+    INPUT:
+    fko_ctx_t ctx;
+    char*   hmac_key;
+    int     hmac_key_len;
+    CODE:
+    RETVAL = fko_verify_hmac(ctx, hmac_key, hmac_key_len);
+    OUTPUT:
+    RETVAL
+
+int
+_calculate_hmac(ctx, hmac_key, hmac_key_len)
+    INPUT:
+    fko_ctx_t ctx;
+    char*   hmac_key;
+    int     hmac_key_len;
+    CODE:
+    RETVAL = fko_calculate_hmac(ctx, hmac_key, hmac_key_len);
+    OUTPUT:
+    RETVAL
+
+int
 _encrypt_spa_data(ctx, enc_key, enc_key_len)
     INPUT:
     fko_ctx_t ctx;
index c941f98..0cddf27 100644 (file)
@@ -73,6 +73,10 @@ sub new {
     my $data      = shift;
     my $dc_pw     = shift;
     my $dc_pw_len = shift;
+    my $enc_mode  = shift;
+    my $hmac_pw   = shift;
+    my $hmac_pw_len = shift;
+    my $hmac_type = shift;
     my $res;
 
     my $ctx;
@@ -82,7 +86,8 @@ sub new {
     #
     if($data) {
         if(defined($dc_pw)) {
-            $ctx = _init_ctx_with_data($data, $dc_pw, $dc_pw_len);
+            $ctx = _init_ctx_with_data($data, $dc_pw, $dc_pw_len,
+                        $enc_mode, $hmac_pw, $hmac_pw_len, $hmac_type);
         } else {
             $ctx = _init_ctx_with_data_only($data);
         }
@@ -166,6 +171,19 @@ sub digest_type {
     return($self->_check_return_val($val));
 }
 
+sub hmac_type {
+    my $self = shift;
+    my $val  = shift;
+
+    return FKO::_set_hmac_type($self->{_ctx}, $val)
+        if(defined($val));
+
+    $val = -1;
+    $self->{_err} = FKO::_get_hmac_type($self->{_ctx}, $val);
+
+    return($self->_check_return_val($val));
+}
+
 sub encryption_type {
     my $self = shift;
     my $val  = shift;
@@ -297,6 +315,22 @@ sub spa_digest {
     return($self->_check_return_val($val));
 }
 
+sub spa_hmac {
+    my $self = shift;
+    my $recompute    = shift || 0;
+    my $hmac_key     = shift || '';
+    my $hmac_key_len = shift || 0;
+
+    my $val = '';
+
+    return FKO::_calculate_hmac($self->{_ctx})
+        if($recompute and $hmac_key and $hmac_key_len);
+
+    $self->{_err} = FKO::_get_spa_hmac($self->{_ctx}, $val);
+
+    return($self->_check_return_val($val));
+}
+
 sub spa_data {
     my $self = shift;
     my $val  = shift;
@@ -476,6 +510,22 @@ sub decode_spa_data {
     return FKO::_decode_spa_data($self->{_ctx});
 }
 
+sub verify_hmac {
+    my $self         = shift;
+    my $hmac_key     = shift || '';
+    my $hmac_key_len = shift || 0;
+
+    return FKO::_verify_hmac($self->{_ctx}, $hmac_key, $hmac_key_len)
+}
+
+sub calculate_hmac {
+    my $self         = shift;
+    my $hmac_key     = shift || '';
+    my $hmac_key_len = shift || 0;
+
+    return FKO::_calculate_hmac($self->{_ctx}, $hmac_key, $hmac_key_len)
+}
+
 sub DESTROY {
     my $self = shift;
     FKO::_destroy_ctx($self->{_ctx}) if($self->{_ctx});
@@ -545,7 +595,7 @@ FKO - Perl module wrapper for libfko
   } elsif($digest_type == FKO::FKO_DIGEST_MD5) {
       # do something else
   }
-  
+
 =head1 DESCRIPTION
 
 This module is essentially a Perl wrapper for the I<Firewall Knock Operator>
index 65ef49c..63170a4 100755 (executable)
@@ -1832,15 +1832,19 @@ sub fuzzing_usernames() {
 
 sub valid_encryption_keys() {
     my @keys = (
+        '!@#$%',
+        'asdfasdfsafsdafasdfasdfsafsdaf',
+#        'asdfasdfsafsdafasdfasdfsafsdaffdjskalfjdskl' .
+#        'afjsldkafjdsajdkajsklfdafsklfjjdkljdsafjdjd' .
+#        'sklfjsfdsafjdslfdkjdljsajdskjdskafjdldsljdk' .
+#        afdsljdslafdslaldldajdskajlddslajsl',
+        '$',
+        'asdfasdfsafsdaf',
         'testtest',
         '12341234',
         '1',
         '1234',
         'a',
-        '$',
-        '!@#$%',
-        'asdfasdfsafsdaf',
-        'asdfasdfsafsdafasdfasdfsafsdaf',
     );
     return \@keys;
 }
@@ -1856,6 +1860,34 @@ sub valid_spa_digest_types() {
     return \@types;
 }
 
+sub valid_spa_hmac_types() {
+    my @types = (
+        FKO->FKO_HMAC_MD5,
+        FKO->FKO_HMAC_SHA1,
+        FKO->FKO_HMAC_SHA256,
+        FKO->FKO_HMAC_SHA384,
+        FKO->FKO_HMAC_SHA512
+    );
+    return \@types;
+}
+
+sub hmac_type_to_str() {
+    my $hmac_type = shift;
+
+    if ($hmac_type == FKO->FKO_HMAC_MD5) {
+        return 'md5';
+    } elsif ($hmac_type == FKO->FKO_HMAC_SHA1) {
+        return 'sha1';
+    } elsif ($hmac_type == FKO->FKO_HMAC_SHA256) {
+        return 'sha256';
+    } elsif ($hmac_type == FKO->FKO_HMAC_SHA384) {
+        return 'sha384';
+    } elsif ($hmac_type == FKO->FKO_HMAC_SHA512) {
+        return 'sha512';
+    }
+    return 'Unknown';
+}
+
 sub fuzzing_spa_digest_types() {
     my @types = (
         -1,
@@ -2116,6 +2148,115 @@ sub perl_fko_module_rijndael_truncated_keys() {
     return $rv;
 }
 
+sub perl_fko_module_complete_cycle_hmac() {
+    my $test_hr = shift;
+
+    my $rv = 1;
+
+    for my $msg (@{valid_access_messages()}) {
+        for my $user (@{valid_usernames()}) {
+            for my $digest_type (@{valid_spa_digest_types()}) {
+                for my $hmac_type (@{valid_spa_hmac_types()}) {
+                    my $key_ctr = 0;
+                    KEY: for my $key (@{valid_encryption_keys()}) {
+                        $key_ctr++;
+                        last KEY if $key_ctr >= 2;
+                        if ($test_hr->{'set_legacy_iv'} eq $YES
+                                and (length($key) > 16)) {
+                            &write_test_file("[.] Legacy IV mode is set, " .
+                                "skipping long key '$key'.\n",
+                                $curr_test_file);
+                            next KEY;
+                        }
+
+                        my $hmac_key_ctr = 0;
+                        HMAC_KEY: for my $hmac_key (@{valid_encryption_keys()}) {
+                            $hmac_key_ctr++;
+                            last HMAC_KEY if $hmac_key_ctr >= 4;
+
+                            if ($test_hr->{'set_legacy_iv'} eq $YES
+                                    and (length($hmac_key) > 16)) {
+                                &write_test_file("[.] Legacy IV mode is set, " .
+                                    "skipping long key '$hmac_key'.\n",
+                                    $curr_test_file);
+                                next HMAC_KEY;
+                            }
+
+                            &write_test_file("[+] msg: $msg, user: $user, " .
+                                "digest type: $digest_type, hmac digest type: " .
+                                "$hmac_type, key: $key, hmac_key: $hmac_key\n",
+                                $curr_test_file);
+
+                            $fko_obj = FKO->new();
+                            unless ($fko_obj) {
+                                &write_test_file("[-] error FKO->new(): " . FKO::error_str() . "\n",
+                                    $curr_test_file);
+                                return 0;
+                            }
+                            $fko_obj->spa_message($msg);
+                            $fko_obj->username($user);
+                            $fko_obj->spa_message_type(FKO->FKO_ACCESS_MSG);
+                            $fko_obj->digest_type($digest_type);
+                            $fko_obj->hmac_type($hmac_type);
+
+                            my $enc_mode = FKO->FKO_ENC_MODE_CBC;
+                            $enc_mode = FKO->FKO_ENC_MODE_CBC_LEGACY_IV
+                                if $test_hr->{'set_legacy_iv'} eq $YES;
+                            $fko_obj->encryption_mode($enc_mode);
+
+                            $fko_obj->spa_data_final($key, length($key), $hmac_key, length($hmac_key));
+
+                            my $encrypted_msg = $fko_obj->spa_data();
+
+                            $fko_obj->destroy();
+
+                            ### now get new object for decryption
+                            $fko_obj = FKO->new($encrypted_msg, $key, length($key),
+                                    $enc_mode, $hmac_key, length($hmac_key), $hmac_type);
+                            unless ($fko_obj) {
+                                &write_test_file("[-] error FKO->new(): " . FKO::error_str() . "\n",
+                                    $curr_test_file);
+                                return 0;
+                            }
+                            $fko_obj->spa_data($encrypted_msg);
+                            $fko_obj->hmac_type($hmac_type);
+                            $fko_obj->encryption_mode($enc_mode);
+                            my $hmac_digest = $fko_obj->spa_hmac();
+
+                            $fko_obj->decrypt_spa_data($key, length($key), $hmac_key, length($hmac_key));
+
+                            if ($msg ne $fko_obj->spa_message()) {
+                                &write_test_file("[-] $msg encrypt/decrypt mismatch\n",
+                                    $curr_test_file);
+                                $rv = 0;
+                            }
+
+                            $fko_obj->destroy();
+
+                            if ($enable_openssl_compatibility_tests) {
+                                unless (&openssl_hmac_verification($encrypted_msg,
+                                        '', $msg, $hmac_key, 0, $hmac_digest,
+                                        &hmac_type_to_str($hmac_type))) {
+                                    $rv = 0;
+                                }
+
+#                                my $flag = $REQUIRE_SUCCESS;
+#                                $flag = $REQUIRE_FAILURE if $test_hr->{'set_legacy_iv'} eq $YES;
+#                                unless (&openssl_enc_verification($encrypted_msg,
+#                                        '', $msg, $key, 0, $flag)) {
+#                                    $rv = 0;
+#                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return $rv;
+}
+
 sub perl_fko_module_complete_cycle() {
     my $test_hr = shift;
 
index 032319d..bed00b3 100644 (file)
     },
     {
         'category' => 'perl FKO module',
+        'subcategory' => 'HMAC encrypt/decrypt',
+        'detail'   => 'libfko complete cycle',
+        'function' => \&perl_fko_module_complete_cycle_hmac,
+        'set_legacy_iv' => $NO,
+        'fatal'    => $NO
+    },
+
+    {
+        'category' => 'perl FKO module',
         'subcategory' => 'encrypt/decrypt',
         'detail'   => 'truncated keys',
         'function' => \&perl_fko_module_rijndael_truncated_keys,