Botan  1.10.9
cms_algo.cpp
Go to the documentation of this file.
1 /*
2 * CMS Algorithm Specific Code
3 * (C) 1999-2007 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #include <botan/cms_enc.h>
9 #include <botan/der_enc.h>
10 #include <botan/sha160.h>
11 #include <botan/cbc.h>
12 #include <botan/filters.h>
13 #include <botan/libstate.h>
14 
15 #if defined(BOTAN_HAS_RC2)
16  #include <botan/rc2.h>
17 #endif
18 
19 namespace Botan {
20 
21 namespace {
22 
23 /*
24 * Wrap a key as specified in RFC 3217
25 */
26 SecureVector<byte> do_rfc3217_wrap(RandomNumberGenerator& rng,
27  const std::string& cipher_name,
28  const SymmetricKey& kek,
29  const SecureVector<byte>& input)
30  {
31  class Flip_Bytes : public Filter
32  {
33  public:
34  std::string name() const { return "Fip_Bytes"; }
35 
36  void write(const byte data[], size_t length)
37  {
38  buf += std::make_pair(data, length);
39  }
40  void end_msg()
41  {
42  for(size_t j = 0; j != buf.size(); j++)
43  send(buf[buf.size()-j-1]);
44  buf.clear();
45  }
46 
47  Flip_Bytes(const SecureVector<byte>& prefix) : buf(prefix) {}
48  private:
49  SecureVector<byte> buf;
50  };
51 
52  Algorithm_Factory& af = global_state().algorithm_factory();
53 
54  const BlockCipher* cipher = af.prototype_block_cipher(cipher_name);
55 
56  if(!cipher || cipher->block_size() != 8)
57  throw Encoding_Error("do_rfc3217_wrap: Bad cipher: " + cipher_name);
58 
59  Pipe icv(new Hash_Filter(new SHA_160, 8));
60  icv.process_msg(input);
61 
62  InitializationVector iv(rng, 8);
63  InitializationVector fixed("4ADDA22C79E82105");
64 
65  Pipe pipe(new CBC_Encryption(cipher->clone(), new Null_Padding, kek, iv),
66  new Flip_Bytes(iv.bits_of()),
67  new CBC_Encryption(cipher->clone(), new Null_Padding, kek, iv));
68 
69  pipe.start_msg();
70  pipe.write(input);
71  pipe.write(icv.read_all());
72  pipe.end_msg();
73  return pipe.read_all();
74  }
75 
76 }
77 
78 /*
79 * Wrap a CEK with a KEK
80 */
81 SecureVector<byte> CMS_Encoder::wrap_key(RandomNumberGenerator& rng,
82  const std::string& cipher,
83  const SymmetricKey& cek,
84  const SymmetricKey& kek)
85  {
86 #if defined(BOTAN_HAS_DES)
87  if(cipher == "TripleDES")
88  {
89  SymmetricKey cek_parity = cek;
90  cek_parity.set_odd_parity();
91  return do_rfc3217_wrap(rng, cipher, kek, cek_parity.bits_of());
92  }
93 #endif
94 
95 #if defined(BOTAN_HAS_RC2) || defined(BOTAN_HAS_CAST)
96  if(cipher == "RC2" || cipher == "CAST-128")
97  {
98  if(kek.length() != 16)
99  throw Encoding_Error("CMS: 128-bit KEKs must be used with " + cipher);
100 
101  SecureVector<byte> lcekpad;
102  lcekpad.push_back(static_cast<byte>(cek.length()));
103  lcekpad += cek.bits_of();
104  while(lcekpad.size() % 8)
105  lcekpad.push_back(rng.next_byte());
106  return do_rfc3217_wrap(rng, cipher, kek, lcekpad);
107  }
108 #endif
109 
110  throw Invalid_Argument("CMS_Encoder::wrap: Unknown cipher " + cipher);
111  }
112 
113 /*
114 * Encode the parameters for an encryption algo
115 */
116 SecureVector<byte> CMS_Encoder::encode_params(const std::string& cipher,
117  const SymmetricKey& key,
118  const InitializationVector& iv)
119  {
120  DER_Encoder encoder;
121 
122 #if defined(BOTAN_HAS_RC2)
123  if(cipher == "RC2")
124  {
125  encoder.start_cons(SEQUENCE).
126  encode(static_cast<size_t>(RC2::EKB_code(8*key.length()))).
127  encode(iv.bits_of(), OCTET_STRING).
128  end_cons();
129  return encoder.get_contents();
130  }
131 #endif
132 
133  if(cipher == "CAST-128")
134  {
135  encoder.start_cons(SEQUENCE).
136  encode(iv.bits_of(), OCTET_STRING).
137  encode(8*key.length()).
138  end_cons();
139  }
140  else
141  encoder.encode(iv.bits_of(), OCTET_STRING);
142 
143  return encoder.get_contents();
144  }
145 
146 /*
147 * Generate a CEK or KEK for the cipher
148 */
149 SymmetricKey CMS_Encoder::setup_key(RandomNumberGenerator& rng,
150  const std::string& cipher)
151  {
152  size_t keysize = 0;
153 
154  if(cipher == "TripleDES") keysize = 24;
155  if(cipher == "RC2") keysize = 16;
156  if(cipher == "CAST-128") keysize = 16;
157 
158  if(keysize == 0)
159  throw Invalid_Argument("CMS: Cannot encrypt with cipher " + cipher);
160 
161  SymmetricKey key(rng, keysize);
162  if(cipher == "DES" || cipher == "TripleDES")
163  key.set_odd_parity();
164  return key;
165  }
166 
167 }
const BlockCipher * prototype_block_cipher(const std::string &algo_spec, const std::string &provider="")
std::invalid_argument Invalid_Argument
Definition: exceptn.h:20
Algorithm_Factory & algorithm_factory() const
Definition: libstate.cpp:173
unsigned char byte
Definition: types.h:22
OctetString SymmetricKey
Definition: symkey.h:147
RandomNumberGenerator * rng
Definition: global_rng.cpp:165
Library_State & global_state()
std::string encode(const byte der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:19
std::string cipher_name
Definition: ossl_bc.cpp:42
static byte EKB_code(size_t bits)
Definition: rc2.cpp:144
OctetString InitializationVector
Definition: symkey.h:152
void set_odd_parity()
Definition: symkey.cpp:47