cmac-rb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,112 @@
1
+ #include <stdio.h>
2
+ #include <string.h>
3
+ #include <openssl/crypto.h>
4
+ #include <openssl/evp.h>
5
+ #include <openssl/aes.h>
6
+
7
+ #include "cmac.h"
8
+
9
+ static void cmac_xor (unsigned char *out, const unsigned char *in) {
10
+
11
+ int i;
12
+
13
+ for (i = 0; i < AES_BLOCK_SIZE; i++) {
14
+ out[i] ^= in[i];
15
+ }
16
+
17
+ }
18
+
19
+ static void cmac_pad (unsigned char *buf, int len) {
20
+
21
+ int i;
22
+
23
+ for ( i = len; i < AES_BLOCK_SIZE; i++ ) {
24
+ buf[i] = (i == len) ? 0x80 : 0x00;
25
+ }
26
+
27
+ }
28
+
29
+ static unsigned char cmac_left_shift(unsigned char *out, unsigned char *in, unsigned char *overflow) {
30
+
31
+ int i;
32
+
33
+ for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
34
+ out[i] = (in[i] << 1) | (*overflow);
35
+ (*overflow) = CMAC_MSB(&in[i]);
36
+ }
37
+
38
+ return;
39
+
40
+ }
41
+
42
+ static void cmac_generate_sub_key(unsigned char *out, unsigned char *in) {
43
+
44
+ int i; unsigned char overflow = 0;
45
+
46
+ cmac_left_shift(out, in, &overflow);
47
+
48
+ if (overflow) {
49
+ out[AES_BLOCK_SIZE-1] ^= 0x87;
50
+ }
51
+
52
+ return;
53
+ }
54
+
55
+
56
+ void cmac_encrypt (cmac_ctx *ctx, const unsigned char *msg, int msg_len, unsigned char *ct) {
57
+
58
+ int n, i, k;
59
+
60
+ unsigned char M[AES_BLOCK_SIZE];
61
+ unsigned char *cursor = (unsigned char *) msg;
62
+
63
+ memcpy(ct, zero_block, AES_BLOCK_SIZE);
64
+ memset(M, 0, AES_BLOCK_SIZE);
65
+
66
+ n = (msg_len + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE - 1;
67
+ k = (msg_len % AES_BLOCK_SIZE);
68
+
69
+ for (i = 0; i < n; i++) {
70
+ cmac_xor(ct, cursor);
71
+ AES_ecb_encrypt(ct, ct, &ctx->cmac_key, AES_ENCRYPT);
72
+ cursor += AES_BLOCK_SIZE;
73
+ }
74
+
75
+ if (k == 0) {
76
+ if (msg != NULL && msg_len != 0) {
77
+ memcpy(M, cursor, AES_BLOCK_SIZE);
78
+ cmac_xor(M, ctx->K1);
79
+ } else {
80
+ cmac_pad(M, 0); cmac_xor(M, ctx->K2);
81
+ }
82
+ } else {
83
+ memcpy(M, cursor, k);
84
+ cmac_pad(M, k); cmac_xor(M, ctx->K2);
85
+ }
86
+
87
+ cmac_xor(ct, M);
88
+
89
+ AES_ecb_encrypt(ct, ct, &ctx->cmac_key, AES_ENCRYPT);
90
+
91
+ return;
92
+
93
+ }
94
+
95
+ int cmac_init (cmac_ctx *ctx, const unsigned char *key, int key_len)
96
+ {
97
+
98
+ unsigned char L[AES_BLOCK_SIZE];
99
+
100
+ memset((char *)ctx, 0, sizeof(cmac_ctx));
101
+
102
+ AES_set_encrypt_key(key, 128, &ctx->cmac_key);
103
+ AES_ecb_encrypt(zero_block, L, &ctx->cmac_key, AES_ENCRYPT);
104
+
105
+ cmac_generate_sub_key(ctx->K1, L);
106
+ cmac_generate_sub_key(ctx->K2, ctx->K1);
107
+
108
+ cmac_encrypt(ctx, zero_block, AES_BLOCK_SIZE, ctx->T);
109
+
110
+ return 1;
111
+
112
+ }
@@ -0,0 +1,23 @@
1
+ #ifndef _CMAC_H_
2
+ #define _CMAC_H_
3
+
4
+ #include <openssl/aes.h>
5
+
6
+ typedef struct _cmac_ctx {
7
+ unsigned char K1[AES_BLOCK_SIZE];
8
+ unsigned char K2[AES_BLOCK_SIZE];
9
+ unsigned char T[AES_BLOCK_SIZE];
10
+ AES_KEY cmac_key;
11
+ } cmac_ctx;
12
+
13
+ #define CMAC_MSB(x) (((x)[0] & 0x80)?1:0)
14
+
15
+ static unsigned char zero_block[AES_BLOCK_SIZE] = {
16
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
18
+ };
19
+
20
+ int cmac_init(cmac_ctx * ctx, const unsigned char * key, int key_len);
21
+ void cmac_encrypt (cmac_ctx * ctx, const unsigned char * msg, int msg_len, unsigned char * ct);
22
+
23
+ #endif
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ dir_config('openssl')
4
+ have_header("openssl/ssl.h")
5
+ have_library("ssl", "SSLv23_method")
6
+ create_makefile('cmac/wrapper')
@@ -0,0 +1,140 @@
1
+ #include <ruby.h>
2
+ #include "cmac.h"
3
+
4
+ // Top-level objects for the native extension
5
+ static VALUE cmac_rb;
6
+ static VALUE cmac_rb_digest;
7
+
8
+ /*
9
+ * Initialize an CMAC::Digest object with a key.
10
+ * Performs basic length validation on the key.
11
+ */
12
+ static VALUE cmac_rb_initialize(VALUE self, VALUE key) {
13
+
14
+ int keyLen;
15
+
16
+ // Replace key value with key.to_str
17
+ StringValue(key);
18
+
19
+ // Get the key length as an int.
20
+ keyLen = RSTRING_LEN(key);
21
+
22
+ // Make sure key is not empty
23
+ if (keyLen == 0) {
24
+ rb_raise(rb_eArgError, "Key must be non-empty.");
25
+ }
26
+
27
+ // Make sure key is acceptable size
28
+ if (keyLen != AES_BLOCK_SIZE) {
29
+ rb_raise(rb_eArgError, "Only 128-bit keys are supported.");
30
+ }
31
+
32
+ // Set key as instance variable
33
+ rb_iv_set(self, "@key", key);
34
+
35
+ return self;
36
+
37
+ }
38
+
39
+ /*
40
+ * Get an cmac_ctx object for the current instance
41
+ * by fetching the @key instance variable, converting
42
+ * it to a byte array and feeding it into cmac_init.
43
+ *
44
+ * Returns 1 upon success, 0 upon failure.
45
+ */
46
+ static int cmac_rb_get_ctx(VALUE self, cmac_ctx* ctx) {
47
+
48
+ VALUE key; unsigned char* cKey; int cKeyLen;
49
+
50
+ // Get the key instance variable
51
+ key = rb_iv_get(self, "@key");
52
+
53
+ // Convert the key to a byte array
54
+ cKey = (unsigned char*) RSTRING_PTR(key);
55
+ cKeyLen = RSTRING_LEN(key);
56
+
57
+ // Initialize the context with the key
58
+ if (cmac_init(ctx, cKey, cKeyLen * 8) < 0) {
59
+ return 0;
60
+ }
61
+
62
+ // Return 1 upon successful initialization
63
+ return 1;
64
+
65
+ }
66
+
67
+ /*
68
+ * Compute the digest of some plaintext
69
+ */
70
+ static VALUE cmac_rb_update(VALUE self, VALUE plaintext) {
71
+
72
+ // Holds the CMAC context object.
73
+ cmac_ctx ctx;
74
+
75
+ // Input plaintext as byte array.
76
+ const unsigned char* cPlaintext;
77
+
78
+ // Length of the input plaintext.
79
+ int cPlaintextLen;
80
+
81
+ // Holds the CMAC ciphertext object.
82
+ unsigned char* cDigest;
83
+
84
+ // Holds the length of the CMAC digest.
85
+ int cDigestLen;
86
+
87
+ // Get the CMAC context based on the instance's key.
88
+ if (!cmac_rb_get_ctx(self, &ctx)) {
89
+ rb_raise(rb_eRuntimeError, "Could not get CMAC context");
90
+ }
91
+
92
+ // Replace the plaintext with plaintext.to_str
93
+ StringValue(plaintext);
94
+
95
+ // Convert the plaintext to a byte array.
96
+ cPlaintext = (const unsigned char*) RSTRING_PTR(plaintext);
97
+ cPlaintextLen = RSTRING_LEN(plaintext);
98
+
99
+ // Allocate space for the ciphertext.
100
+ cDigestLen = sizeof(unsigned char) * AES_BLOCK_SIZE;
101
+ cDigest = (unsigned char*) malloc(cDigestLen);
102
+
103
+ // Call aes_cmac with all parameters.
104
+ cmac_encrypt(&ctx, cPlaintext, cPlaintextLen, cDigest);
105
+
106
+ // Return a new Ruby string with the resulting value.
107
+ return rb_str_new((const char*) cDigest, cDigestLen);
108
+
109
+ }
110
+
111
+ /*
112
+ * Main wrapper for the CMAC Ruby native extension.
113
+ */
114
+ void Init_wrapper(void) {
115
+
116
+ // Define the top-level module
117
+ cmac_rb = rb_define_module("CMAC");
118
+
119
+ // Define the cipher class
120
+ cmac_rb_digest = rb_define_class_under(cmac_rb, "Digest", rb_cObject);
121
+
122
+ // Define the implemented methods.
123
+ rb_define_method(cmac_rb_digest, "initialize", cmac_rb_initialize, 1);
124
+ rb_define_method(cmac_rb_digest, "update", cmac_rb_update, 1);
125
+
126
+ return;
127
+
128
+ }
129
+
130
+ /*
131
+ Debug helper method to print byte arrays in hex format.
132
+
133
+ void print_hex(const char* header, const unsigned char *bytes, int len) {
134
+
135
+ int i = 0; printf("\n%s (%d): ", header, len);
136
+ for (i = 0; i < len; ++i) printf("%x", bytes[i]);
137
+ printf("\n");
138
+
139
+ }
140
+ */
@@ -0,0 +1,2 @@
1
+ require 'cmac-rb/wrapper'
2
+ require 'cmac-rb/version'
@@ -0,0 +1,3 @@
1
+ module CMAC
2
+ VERSION = '0.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cmac-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Louis Mullie
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-04-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.12.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 2.12.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: ! ' Ruby C extension for the AES-CMAC keyed hash function. '
47
+ email:
48
+ - louis.mullie@gmail.com
49
+ executables: []
50
+ extensions:
51
+ - ext/cmac/extconf.rb
52
+ extra_rdoc_files: []
53
+ files:
54
+ - lib/cmac-rb/version.rb
55
+ - lib/cmac-rb.rb
56
+ - ext/cmac/cmac.c
57
+ - ext/cmac/wrapper.c
58
+ - ext/cmac/cmac.h
59
+ - ext/cmac/extconf.rb
60
+ homepage: https://github.com/cryodex/cmac-rb
61
+ licenses: []
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 1.8.25
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Ruby C extension for the AES-CMAC keyed hash function.
84
+ test_files: []