Class: SIV::Cipher

Inherits:
Object
  • Object
show all
Defined in:
lib/siv-rb.rb,
ext/siv/wrapper.c

Instance Method Summary collapse

Constructor Details

#initialize(key) ⇒ Object

Initialize an SIV::Cipher object with a key. Performs basic length validation on the key.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'ext/siv/wrapper.c', line 15

static VALUE siv_rb_initialize(VALUE self, VALUE key) {
 
  int keyLen;
  
  // Replace key value with key.to_str
  StringValue(key);
  
  // Get the key length as an int.
  keyLen = RSTRING_LEN(key);
  
  // Make sure key is not empty
  if (keyLen == 0) {
    rb_raise(rb_eArgError, "Key must be non-empty.");
  }
  
  // Make sure key is acceptable size
  if (keyLen * 8 != SIV_256 &&
      keyLen * 8 != SIV_384 &&
      keyLen * 8 != SIV_512) {
    rb_raise(rb_eArgError, "Supported key sizes are 256, 384 and 512 bits.");
  }
  
  // Set key as instance variable
  rb_iv_set(self, "@key", key);
  
  return self;
  
}

Instance Method Details

#decrypt(ct, ad = []) ⇒ Object



12
13
14
# File 'lib/siv-rb.rb', line 12

def decrypt(ct, ad = [])
  decrypt_native(ct, ad)
end

#decrypt_native(ciphertext, associated) ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'ext/siv/wrapper.c', line 201

static VALUE siv_rb_decrypt(VALUE self, VALUE ciphertext, VALUE associated) {
  
  siv_ctx ctx;
  
  // Holds the counter object bytes
  unsigned char cCounter[AES_BLOCK_SIZE];
  
  // Holds the iv + ciphertext bytes
  const unsigned char* cCiphertext;
  int cCiphertextLen;
  
  // Holds the ciphertext-only bytes
  unsigned char* cCiphertextTrunc;
  int j; int cCiphertextTruncLen;
  
  // Receives the plaintext bytes
  const unsigned char* cPlaintext;
  
  // Holds associated-data
  int cAdNum; int* cAdLens;
  unsigned char** cAds;
  
  // Get the SIV context with the key
  if (!siv_rb_get_ctx(self, &ctx)) {
    rb_raise(rb_eRuntimeError, "Could not get SIV context");
  }
  
  // Get the ciphertext bytes and length
  StringValue(ciphertext);
  cCiphertext = (unsigned char*) RSTRING_PTR(ciphertext);
  cCiphertextLen = RSTRING_LEN(ciphertext);
  
  // Truncate the IV (counter) off the ciphertext
  cCiphertextTrunc = (unsigned char*) malloc(
    SIV_UCHAR_SIZE * (cCiphertextLen - AES_BLOCK_SIZE));
  cCiphertextTruncLen = cCiphertextLen - AES_BLOCK_SIZE;
  
  // Iterate through the ciphertext to truncate
  for (j = 0; j < cCiphertextLen; j++) {
    if (j < AES_BLOCK_SIZE) cCounter[j] = cCiphertext[j];
    else cCiphertextTrunc[j - AES_BLOCK_SIZE] = cCiphertext[j];
  }
  
  // Get the number of associated data items in the array.
  cAdNum = (int) RARRAY_LEN(associated);
  cAdLens = (int *) malloc(sizeof(int) * cAdNum);
  cAds = (unsigned char **) malloc(sizeof(unsigned char*) * cAdNum);
  
  // Get the associated data lengths and data arrays
  if (!siv_rb_get_associated(associated, cAdLens, cAds)) {
    rb_raise(rb_eRuntimeError, "Could not get associated data");
  }
  
  // Allocate space to receive the plaintext.
  cPlaintext = (unsigned char*) malloc(SIV_UCHAR_SIZE * cCiphertextTruncLen);
  
  // Decrypt the ciphertext using SIV.
  if (siv_decrypt(&ctx, cCiphertextTrunc, cPlaintext,
      (const int) cCiphertextTruncLen, cCounter,
      (const int) cAdNum, cAdLens, cAds) < 0) {
    rb_raise(rb_eRuntimeError, "SIV decryption failed");
  }
  
  // Free up dynamically allocated memory.
  free(cAdLens); free(cAds); free(cCiphertextTrunc);
  
  // Build and return a Ruby string object with the plaintext
  return rb_str_new((const char*) cPlaintext, cCiphertextTruncLen);
  
}

#encrypt(pt, ad = []) ⇒ Object



8
9
10
# File 'lib/siv-rb.rb', line 8

def encrypt(pt, ad = [])
  encrypt_native(pt, ad)
end

#encrypt_native(plaintext, associated) ⇒ Object

Encrypt a plaintext and some associated data



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'ext/siv/wrapper.c', line 126

static VALUE siv_rb_encrypt(VALUE self, VALUE plaintext, VALUE associated) {
  
  // Holds the SIV context object.
  siv_ctx ctx;
  
  // Input plaintext as byte array.
  const unsigned char* cPlaintext;
  
  // Length of the input plaintext.
  int cPlaintextLen;
  
  // Holds the SIV counter object.
  unsigned char cCounter[AES_BLOCK_SIZE];
  
  // Holds the SIV ciphertext object.
  unsigned char* cCiphertext;
  
  // Hold the parsed associated data.
  int cAdNum; int* cAdLens; unsigned char** cAds;
  
  // For concatenation of IV with data.
  unsigned char* cOutput;
  int cOutputLen; int outputInd;
  
  // Get the SIV context based on the instance's key.
  if (!siv_rb_get_ctx(self, &ctx)) {
    rb_raise(rb_eRuntimeError, "Could not get SIV context");
  }
  
  // Replace the plaintext with plaintext.to_str
  StringValue(plaintext);
  
  // Convert the plaintext to a byte array.
  cPlaintext = (const unsigned char*) RSTRING_PTR(plaintext);
  
  // Get the length of the plaintext as an int.
  cPlaintextLen = RSTRING_LEN(plaintext);
  
  cAdNum = (int) RARRAY_LEN(associated);
  cAdLens = (int *) malloc(sizeof(int) * cAdNum);
  cAds = (unsigned char **) malloc(sizeof(unsigned char*) * cAdNum);
  
  // Get the parsed associated data values.
  if (!siv_rb_get_associated(associated, cAdLens, cAds)) {
    rb_raise(rb_eRuntimeError, "Could not get associated data");
  }
  
  // Allocate space for the ciphertext.
  cCiphertext = (unsigned char*) malloc(SIV_UCHAR_SIZE * cPlaintextLen);
  
  // Call siv_encrypt with all parameters.
  if (siv_encrypt( &ctx, cPlaintext, cCiphertext,
                  (const int) cPlaintextLen, cCounter,
                  (const int) cAdNum, cAdLens, cAds) < 0) {
    rb_raise(rb_eRuntimeError, "SIV encryption failed");
  }
  
  // Prepend the IV (counter) to the ciphertext.
  cOutputLen = cPlaintextLen + AES_BLOCK_SIZE;
  cOutput = (unsigned char*) malloc(SIV_UCHAR_SIZE * cOutputLen);
  
  // Iterate through the output to prepend the iv.
  for (outputInd = 0; outputInd < cOutputLen; ++outputInd) {
    cOutput[outputInd] = (outputInd < AES_BLOCK_SIZE) ?
    cCounter[outputInd] : cCiphertext[outputInd - AES_BLOCK_SIZE];
  }
  
  // Free up dynamically allocated memory.
  free(cAdLens); free(cAds); free(cCiphertext);
  
  // Return a new Ruby string with the resulting value.
  return rb_str_new((const char*) cOutput, cOutputLen);
  
}