cmac-rb 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []