aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2013-03-16 22:23:59 +0000
committerlloyd <[email protected]>2013-03-16 22:23:59 +0000
commit158b20308dcc5c81e712e2e496fa0a5944e484a4 (patch)
treeb797fed9a06ba62f57b4c6d771d389c493f6ab0c
parent01d1a8f734b9912301e4c0b6504c5ffa1d09e27a (diff)
Working GCM. Add support for AEAD modes in self tests
-rw-r--r--checks/bench.cpp29
-rw-r--r--checks/validate.cpp3
-rw-r--r--checks/validate.dat91
-rw-r--r--src/filters/modes/gcm/gcm.cpp113
-rw-r--r--src/filters/modes/gcm/gcm.h6
-rw-r--r--src/selftest/selftest.cpp40
-rw-r--r--src/stream/stream_cipher.h4
7 files changed, 172 insertions, 114 deletions
diff --git a/checks/bench.cpp b/checks/bench.cpp
index f7ddc5650..96afd7d87 100644
--- a/checks/bench.cpp
+++ b/checks/bench.cpp
@@ -62,46 +62,23 @@ const std::string algos[] = {
"Luby-Rackoff(SHA-512)",
/* Cipher modes */
- "TripleDES/CBC/PKCS7",
- "TripleDES/CBC/CTS",
- "TripleDES/CTR-BE",
- "TripleDES/EAX",
- "TripleDES/OFB",
- "TripleDES/CFB(64)",
- "TripleDES/CFB(32)",
- "TripleDES/CFB(16)",
- "TripleDES/CFB(8)",
-
"AES-128/CBC/PKCS7",
- "AES-128/CBC/CTS",
"AES-128/CTR-BE",
"AES-128/EAX",
"AES-128/OCB",
- "AES-128/OFB",
+ "AES-128/GCM",
"AES-128/XTS",
- "AES-128/CFB(128)",
- "AES-128/CFB(64)",
- "AES-128/CFB(32)",
- "AES-128/CFB(16)",
- "AES-128/CFB(8)",
"Serpent/CBC/PKCS7",
- "Serpent/CBC/CTS",
"Serpent/CTR-BE",
"Serpent/EAX",
- "Serpent/OFB",
+ "Serpent/OCB",
+ "Serpent/GCM",
"Serpent/XTS",
- "Serpent/CFB(128)",
- "Serpent/CFB(64)",
- "Serpent/CFB(32)",
- "Serpent/CFB(16)",
- "Serpent/CFB(8)",
/* Stream ciphers */
"ARC4",
"Salsa20",
- "Turing",
- "WiderWake4+1-BE",
/* Checksums */
"Adler32",
diff --git a/checks/validate.cpp b/checks/validate.cpp
index 60fd729e3..7ae2fba29 100644
--- a/checks/validate.cpp
+++ b/checks/validate.cpp
@@ -442,6 +442,9 @@ bool failed_test(const std::string& algo,
if(params.size() > 3)
vars["iv"] = params[3];
+ if(params.size() > 4)
+ vars["ad"] = params[4];
+
Algorithm_Factory& af = global_state().algorithm_factory();
const auto results = algorithm_kat_detailed(algo, vars, af);
diff --git a/checks/validate.dat b/checks/validate.dat
index affd59c7c..e7526e817 100644
--- a/checks/validate.dat
+++ b/checks/validate.dat
@@ -26292,19 +26292,94 @@ C61A0851AB4E515D11525B92E2B9D850:C825FC7C4D539DC74887CECC70884F37
F956B879EC7F807F1FCB482B53623671:E64F90B4619D93137E6237929EABF297
[AES-128/GCM]
-#:58E2FCCEFA7E3061367F1D57A4E7455A:\
-#00000000000000000000000000000000:000000000000000000000000
+:58E2FCCEFA7E3061367F1D57A4E7455A:\
+00000000000000000000000000000000:000000000000000000000000
00000000000000000000000000000000:\
0388DACE60B6A392F328C2B971B2FE78AB6E47D42CEC13BDF53A67B21257BDDF:\
00000000000000000000000000000000:000000000000000000000000
-#D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A72\
-#1C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B391AAFD255:\
-#42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E\
-#21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091473F5985\
-#4D5C2AF327CD64A62CF35ABD2BA6FAB4:\
-#FEFFE9928665731C6D6A8F9467308308:CAFEBABEFACEDBADDECAF888
+D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A72\
+1C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B391AAFD255:\
+42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E\
+21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091473F5985\
+4D5C2AF327CD64A62CF35ABD2BA6FAB4:\
+FEFFE9928665731C6D6A8F9467308308:CAFEBABEFACEDBADDECAF888
+
+D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A72\
+1C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39:\
+42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E\
+21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091\
+5BC94FBC3221A5DB94FAE95AE7121A47:\
+FEFFE9928665731C6D6A8F9467308308:\
+CAFEBABEFACEDBADDECAF888:\
+FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2
+
+D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A72\
+1C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39:\
+61353B4C2806934A777FF51FA22A4755699B2A714FCDC6F83766E5F97B6C7423\
+73806900E49F24B22B097544D4896B424989B5E1EBAC0F07C23F4598\
+3612D2E79E3B0785561BE14AACA2FCCB:\
+FEFFE9928665731C6D6A8F9467308308:\
+CAFEBABEFACEDBAD:\
+FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2
+
+D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A72\
+1C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39:\
+8CE24998625615B603A033ACA13FB894BE9112A5C3A211A8BA262A3CCA7E2CA7\
+01E4A9A4FBA43C90CCDCB281D48C7C6FD62875D2ACA417034C34AEE5\
+619CC5AEFFFE0BFA462AF43C1699D050:\
+FEFFE9928665731C6D6A8F9467308308:\
+9313225DF88406E555909C5AFF5269AA6A7A9538534F7DA1E4C303D2A318A728\
+C3C0C95156809539FCF0E2429A6B525416AEDBF5A0DE6A57A637B39B:\
+FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2
+
+# From Crypto++ 5.6.1
+006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\
+130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\
+006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\
+130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\
+006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\
+130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\
+006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\
+130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\
+006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\
+130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\
+006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\
+130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\
+006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\
+130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\
+006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\
+130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\
+006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\
+130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\
+006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\
+130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710\
+006BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5\
+130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710:\
+BD70C168B0D4371B0A85B4B5D65D92569B17\
+F9A3D0A25B9F608E2C34621CF4D37357845431E04E585CDAAD7527BF8A2426DEEF451320C78D5EF0\
+9F5B11A8B8C700CD329A3D4CDED92C20F6BF28CB3627681C5B0AF2B5692CC7EC9049008ACBBD127A\
+9CD8DEF00425697E0BCF67E05AEE70EA1A5D7EE95E3B88FBAF3C196AAAECB73E09BDF057AF701A02\
+42394BCC104FF4F75F15D287325FCFFDB7E7FF3A939A80A6A3A9D7570E6EF6AD0BBE6E291338938D\
+2FEBBC7D5EE95CD73E752ACD48915DCAE0A0807E6F4B2ADADBD945667318264EF7D8C2ECC0B8FB67\
+A43614C5F5EA51CADD4AEE91DC371A7FC5A3B4581D1D9DD99608CD2BB0338F82933C19F5B8EBAD6B\
+BA583835FBD29136302BAC163F86CA9E3E6F3B5BFDEFAB3E4B019190AE2EBC0B71034EA9BF882879\
+139FFE76DD997F6729425F3D5C5392762C245769D18CC963C92211B71F564203AFBF68626C083303\
+1D449B02DFA5C0F09FAFCE951FE35F4AD8122AB682A4AF28931113F75615E12DB05DD9247973F1C6\
+057666848C13EDE41192F38948366D468D84CAF896EFF724082D2BAB2376E2813B41A014999B0EE7\
+377758715D9554926AB3514EEB96A0ABD501D94A05692D858190D5AD307CEB6E6C8A63841A8257BE\
+C2527C4B937840AA51292E15834AB801F0275A6A4B1B6E969B7A7FCE217D6F823CDE1760F847E8F4\
+6CBDE152A24F2319EC2A7089D2954259D30332089FF928034391D1B0B8AFD7C8A5D4F8E0DAB5883C\
+A7D581F78E4848DC3B01E5F2A5C01BA8910D0F144BC494E29450271174B866868EE8DC6B0DD396ED\
+9D72F83DE3BB6DE6FEBC64178961E011D0D746C2CE3A0FBD05CDF8FA79AC03E94C88368BD903E142\
+7FCFC30C9D100E220B4CB9B7BA242DA49D334E930B6C4EB877D1DF2C0F8CF4AF7813E2F295929707\
+19846FC52A47FCE6E71DC5E58FC5F49C91BDE56B7A2A68CFA994D6BFA5357A8403A2B37C69A6A0A4\
+35E4AB4C9E450473AF0CDFDBCC238A2DD7\
+4FEA89D75727E82B3A9F9EEB5E217A3E:\
+2B7E151628AED2A6ABF7158809CF4F3C:\
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+
[AES-128/XTS]
# Vectors are from IEEE P1619 D11
diff --git a/src/filters/modes/gcm/gcm.cpp b/src/filters/modes/gcm/gcm.cpp
index c88a90cdf..527310069 100644
--- a/src/filters/modes/gcm/gcm.cpp
+++ b/src/filters/modes/gcm/gcm.cpp
@@ -10,64 +10,45 @@
#include <botan/internal/xor_buf.h>
#include <botan/loadstor.h>
-#include <iostream>
-#include <botan/hex.h>
-
namespace Botan {
-void dump(const std::string& name, const byte x[], size_t x_len)
- {
- std::cout << name << " = " << hex_encode(x, x_len) << "\n";
- }
-
-void dump(const std::string& name, const secure_vector<byte>& x)
- {
- dump(name, &x[0], x.size());
- }
-
-bool rightshift(secure_vector<byte>& x)
- {
- byte carry = 0;
-
- for(size_t i = 0; i != x.size(); ++i)
- {
- byte carry2 = x[i] & 1;
- x[i] = (x[i] >> 1) | (carry << 7);
- carry = carry2;
- }
-
- return carry;
- }
-
-bool get_bit(const secure_vector<byte>& x, size_t bit)
- {
- const byte b = x[16 - (bit / 8)];
-
- return (b >> (bit % 8)) & 0x01;
- }
-
secure_vector<byte>
gcm_multiply(const secure_vector<byte>& x,
const secure_vector<byte>& y)
{
- secure_vector<byte> z(x.size());
- secure_vector<byte> v = x;
+ static const u64bit R = 0xE100000000000000;
+
+ u64bit V[2] = {
+ load_be<u64bit>(&y[0], 0),
+ load_be<u64bit>(&y[0], 1)
+ };
+
+ u64bit Z[2] = { 0, 0 };
- for(size_t i = 0; i != 128; ++i)
+ for(size_t i = 0; i != 2; ++i)
{
- if(get_bit(y, i))
- z ^= v;
+ u64bit X = load_be<u64bit>(&x[0], i);
- const bool highbit = get_bit(v, 127);
+ for(size_t j = 0; j != 64; ++j)
+ {
+ if(X >> 63)
+ {
+ Z[0] ^= V[0];
+ Z[1] ^= V[1];
+ }
- const bool carry = rightshift(v);
- BOTAN_ASSERT(carry == highbit, "That makes sense");
+ const u64bit r = (V[1] & 1) ? R : 0;
- if(highbit)
- v[0] ^= 0xE1;
+ V[1] = (V[0] << 63) | (V[1] >> 1);
+ V[0] = (V[0] >> 1) ^ r;
+
+ X <<= 1;
+ }
}
- return z;
+ secure_vector<byte> out(16);
+ store_be<u64bit>(&out[0], Z[0], Z[1]);
+ return out;
}
void ghash_update(const secure_vector<byte>& H,
@@ -76,10 +57,6 @@ void ghash_update(const secure_vector<byte>& H,
{
const size_t BS = 16;
- dump("H", H);
-
- dump("ghash-in", ghash);
-
/*
This assumes if less than block size input then we're just on the
final block and should pad with zeros
@@ -88,14 +65,10 @@ void ghash_update(const secure_vector<byte>& H,
{
const size_t to_proc = std::min(length, BS);
- dump("input", input, to_proc);
-
xor_buf(&ghash[0], &input[0], to_proc);
ghash = gcm_multiply(ghash, H);
- dump("X", ghash);
-
input += to_proc;
length -= to_proc;
}
@@ -107,9 +80,7 @@ void ghash_finalize(const secure_vector<byte>& H,
{
secure_vector<byte> final_block(16);
store_be<u64bit>(&final_block[0], 8*ad_len, 8*text_len);
- dump("lens", final_block);
ghash_update(H, ghash, &final_block[0], final_block.size());
- dump("final ghash", ghash);
}
/*
@@ -118,10 +89,14 @@ void ghash_finalize(const secure_vector<byte>& H,
GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting) :
Buffered_Filter(cipher->parallel_bytes(), decrypting ? tag_size : 0),
m_tag_size(tag_size), m_cipher_name(cipher->name()),
- m_H(16), m_H_ad(16), m_H_current(16),
+ m_H(16), m_H_ad(16), m_mac(16),
m_ad_len(0), m_text_len(0),
m_ctr_buf(8 * cipher->parallel_bytes())
{
+ if(cipher->block_size() != BS)
+ throw std::invalid_argument("OCB requires a 128 bit cipher so cannot be used with " +
+ cipher->name());
+
m_ctr.reset(new CTR_BE(cipher)); // CTR_BE takes ownership of cipher
if(m_tag_size < 8 || m_tag_size > 16)
@@ -142,7 +117,7 @@ void GCM_Mode::set_key(const SymmetricKey& key)
{
m_ctr->set_key(key);
- const std::vector<byte> zeros(16);
+ const std::vector<byte> zeros(BS);
m_ctr->set_iv(&zeros[0], zeros.size());
zeroise(m_H);
@@ -165,7 +140,7 @@ void GCM_Mode::set_associated_data(const byte ad[], size_t ad_len)
*/
void GCM_Mode::set_nonce(const byte nonce[], size_t nonce_len)
{
- secure_vector<byte> y0(16);
+ secure_vector<byte> y0(BS);
if(nonce_len == 12)
{
@@ -180,8 +155,8 @@ void GCM_Mode::set_nonce(const byte nonce[], size_t nonce_len)
m_ctr->set_iv(&y0[0], y0.size());
- m_y0_cipher.resize(16);
- m_ctr->cipher(&m_y0_cipher[0], &m_y0_cipher[0], m_y0_cipher.size());
+ m_enc_y0.resize(BS);
+ m_ctr->encipher(m_enc_y0);
}
/*
@@ -190,7 +165,7 @@ void GCM_Mode::set_nonce(const byte nonce[], size_t nonce_len)
void GCM_Mode::start_msg()
{
m_text_len = 0;
- m_H_current = m_H_ad;
+ m_mac = m_H_ad;
}
/*
@@ -218,7 +193,7 @@ void GCM_Encryption::buffered_block(const byte input[], size_t length)
size_t copied = std::min<size_t>(length, m_ctr_buf.size());
m_ctr->cipher(input, &m_ctr_buf[0], copied);
- ghash_update(m_H, m_H_current, &m_ctr_buf[0], copied);
+ ghash_update(m_H, m_mac, &m_ctr_buf[0], copied);
m_text_len += copied;
send(m_ctr_buf, copied);
@@ -232,11 +207,11 @@ void GCM_Encryption::buffered_final(const byte input[], size_t input_length)
{
buffered_block(input, input_length);
- ghash_finalize(m_H, m_H_current, m_ad_len, m_text_len);
+ ghash_finalize(m_H, m_mac, m_ad_len, m_text_len);
- m_H_current ^= m_y0_cipher;
+ m_mac ^= m_enc_y0;
- send(m_H_current, m_tag_size);
+ send(m_mac, m_tag_size);
}
void GCM_Decryption::buffered_block(const byte input[], size_t length)
@@ -245,7 +220,7 @@ void GCM_Decryption::buffered_block(const byte input[], size_t length)
{
size_t copied = std::min<size_t>(length, m_ctr_buf.size());
- ghash_update(m_H, m_H_current, &input[0], copied);
+ ghash_update(m_H, m_mac, &input[0], copied);
m_ctr->cipher(input, &m_ctr_buf[0], copied);
m_text_len += copied;
@@ -266,11 +241,11 @@ void GCM_Decryption::buffered_final(const byte input[], size_t input_length)
if(input_length) // handle any remaining input
buffered_block(input, input_length);
- ghash_finalize(m_H, m_H_current, m_ad_len, m_text_len);
+ ghash_finalize(m_H, m_mac, m_ad_len, m_text_len);
- m_H_current ^= m_y0_cipher;
+ m_mac ^= m_enc_y0;
- if(!same_mem(&m_H_current[0], included_tag, m_tag_size))
+ if(!same_mem(&m_mac[0], included_tag, m_tag_size))
throw Integrity_Failure("GCM tag check failed");
}
diff --git a/src/filters/modes/gcm/gcm.h b/src/filters/modes/gcm/gcm.h
index 3d00577aa..fa13597ce 100644
--- a/src/filters/modes/gcm/gcm.h
+++ b/src/filters/modes/gcm/gcm.h
@@ -41,14 +41,16 @@ class BOTAN_DLL GCM_Mode : public AEAD_Mode,
protected:
GCM_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting);
+ static const size_t BS = 16;
+
const size_t m_tag_size;
const std::string m_cipher_name;
std::unique_ptr<StreamCipher> m_ctr;
secure_vector<byte> m_H;
secure_vector<byte> m_H_ad;
- secure_vector<byte> m_H_current;
- secure_vector<byte> m_y0_cipher;
+ secure_vector<byte> m_mac;
+ secure_vector<byte> m_enc_y0;
size_t m_ad_len, m_text_len;
secure_vector<byte> m_ctr_buf;
diff --git a/src/selftest/selftest.cpp b/src/selftest/selftest.cpp
index 4be0fa4cf..e291a8e9d 100644
--- a/src/selftest/selftest.cpp
+++ b/src/selftest/selftest.cpp
@@ -1,12 +1,14 @@
/*
* Startup Self Tests
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2007,2013 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
#include <botan/selftest.h>
#include <botan/filters.h>
+#include <botan/aead.h>
+#include <botan/hex.h>
#include <botan/internal/core_engine.h>
#include <botan/internal/stl_util.h>
@@ -23,17 +25,24 @@ std::string test_filter_kat(Filter* filter,
const std::string& input,
const std::string& expected)
{
- Pipe pipe(new Hex_Decoder, filter, new Hex_Encoder);
- pipe.process_msg(input);
+ try
+ {
+ Pipe pipe(new Hex_Decoder, filter, new Hex_Encoder);
+ pipe.process_msg(input);
- const std::string got = pipe.read_all_as_string();
+ const std::string got = pipe.read_all_as_string();
- const bool same = (got == expected);
+ const bool same = (got == expected);
- if(same)
- return "passed";
- else
- return (std::string("got ") + got + " expected " + expected);
+ if(same)
+ return "passed";
+ else
+ return (std::string("got ") + got + " expected " + expected);
+ }
+ catch(std::exception& e)
+ {
+ return std::string("exception ") + e.what();
+ }
}
}
@@ -117,6 +126,19 @@ algorithm_kat_detailed(const SCAN_Name& algo_name,
else if(!dec->valid_iv_length(0))
throw Invalid_IV_Length(algo, iv.length());
+#if defined(BOTAN_HAS_AEAD)
+
+ if(AEAD_Mode* enc_aead = dynamic_cast<AEAD_Mode*>(enc))
+ {
+ const std::vector<byte> ad = hex_decode(search_map(vars, std::string("ad")));
+
+ enc_aead->set_associated_data(&ad[0], ad.size());
+
+ if(AEAD_Mode* dec_aead = dynamic_cast<AEAD_Mode*>(dec))
+ dec_aead->set_associated_data(&ad[0], ad.size());
+ }
+#endif
+
all_results[provider + " (encrypt)"] = test_filter_kat(enc, input, output);
all_results[provider + " (decrypt)"] = test_filter_kat(dec, output, input);
}
diff --git a/src/stream/stream_cipher.h b/src/stream/stream_cipher.h
index 301e71f07..231414589 100644
--- a/src/stream/stream_cipher.h
+++ b/src/stream/stream_cipher.h
@@ -34,6 +34,10 @@ class BOTAN_DLL StreamCipher : public SymmetricAlgorithm
void cipher1(byte buf[], size_t len)
{ cipher(buf, buf, len); }
+ template<typename Alloc>
+ void encipher(std::vector<byte, Alloc>& inout)
+ { cipher(&inout[0], &inout[0], inout.size()); }
+
/**
* Resync the cipher using the IV
* @param iv the initialization vector