1 /*
2 * Stream Ciphers
3 * (C) 2015,2016 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/stream_cipher.h>
9 #include <botan/scan_name.h>
10 #include <botan/exceptn.h>
11 
12 #if defined(BOTAN_HAS_CHACHA)
13   #include <botan/chacha.h>
14 #endif
15 
16 #if defined(BOTAN_HAS_SALSA20)
17   #include <botan/salsa20.h>
18 #endif
19 
20 #if defined(BOTAN_HAS_SHAKE_CIPHER)
21   #include <botan/shake_cipher.h>
22 #endif
23 
24 #if defined(BOTAN_HAS_CTR_BE)
25   #include <botan/ctr.h>
26 #endif
27 
28 #if defined(BOTAN_HAS_OFB)
29   #include <botan/ofb.h>
30 #endif
31 
32 #if defined(BOTAN_HAS_RC4)
33   #include <botan/rc4.h>
34 #endif
35 
36 #if defined(BOTAN_HAS_OPENSSL)
37   #include <botan/internal/openssl.h>
38 #endif
39 
40 namespace Botan {
41 
create(const std::string & algo_spec,const std::string & provider)42 std::unique_ptr<StreamCipher> StreamCipher::create(const std::string& algo_spec,
43                                                    const std::string& provider)
44    {
45    const SCAN_Name req(algo_spec);
46 
47 #if defined(BOTAN_HAS_CTR_BE)
48    if((req.algo_name() == "CTR-BE" || req.algo_name() == "CTR") && req.arg_count_between(1,2))
49       {
50       if(provider.empty() || provider == "base")
51          {
52          auto cipher = BlockCipher::create(req.arg(0));
53          if(cipher)
54             {
55             size_t ctr_size = req.arg_as_integer(1, cipher->block_size());
56             return std::unique_ptr<StreamCipher>(new CTR_BE(cipher.release(), ctr_size));
57             }
58          }
59       }
60 #endif
61 
62 #if defined(BOTAN_HAS_CHACHA)
63    if(req.algo_name() == "ChaCha")
64       {
65       if(provider.empty() || provider == "base")
66          return std::unique_ptr<StreamCipher>(new ChaCha(req.arg_as_integer(0, 20)));
67       }
68 
69    if(req.algo_name() == "ChaCha20")
70       {
71       if(provider.empty() || provider == "base")
72          return std::unique_ptr<StreamCipher>(new ChaCha(20));
73       }
74 #endif
75 
76 #if defined(BOTAN_HAS_SALSA20)
77    if(req.algo_name() == "Salsa20")
78       {
79       if(provider.empty() || provider == "base")
80          return std::unique_ptr<StreamCipher>(new Salsa20);
81       }
82 #endif
83 
84 #if defined(BOTAN_HAS_SHAKE_CIPHER)
85    if(req.algo_name() == "SHAKE-128" || req.algo_name() == "SHAKE-128-XOF")
86       {
87       if(provider.empty() || provider == "base")
88          return std::unique_ptr<StreamCipher>(new SHAKE_128_Cipher);
89       }
90 #endif
91 
92 #if defined(BOTAN_HAS_OFB)
93    if(req.algo_name() == "OFB" && req.arg_count() == 1)
94       {
95       if(provider.empty() || provider == "base")
96          {
97          if(auto c = BlockCipher::create(req.arg(0)))
98             return std::unique_ptr<StreamCipher>(new OFB(c.release()));
99          }
100       }
101 #endif
102 
103 #if defined(BOTAN_HAS_RC4)
104 
105    if(req.algo_name() == "RC4" ||
106       req.algo_name() == "ARC4" ||
107       req.algo_name() == "MARK-4")
108       {
109       const size_t skip = (req.algo_name() == "MARK-4") ? 256 : req.arg_as_integer(0, 0);
110 
111 #if defined(BOTAN_HAS_OPENSSL)
112       if(provider.empty() || provider == "openssl")
113          {
114          return std::unique_ptr<StreamCipher>(make_openssl_rc4(skip));
115          }
116 #endif
117 
118       if(provider.empty() || provider == "base")
119          {
120          return std::unique_ptr<StreamCipher>(new RC4(skip));
121          }
122       }
123 
124 #endif
125 
126    BOTAN_UNUSED(req);
127    BOTAN_UNUSED(provider);
128 
129    return nullptr;
130    }
131 
132 //static
133 std::unique_ptr<StreamCipher>
create_or_throw(const std::string & algo,const std::string & provider)134 StreamCipher::create_or_throw(const std::string& algo,
135                              const std::string& provider)
136    {
137    if(auto sc = StreamCipher::create(algo, provider))
138       {
139       return sc;
140       }
141    throw Lookup_Error("Stream cipher", algo, provider);
142    }
143 
providers(const std::string & algo_spec)144 std::vector<std::string> StreamCipher::providers(const std::string& algo_spec)
145    {
146    return probe_providers_of<StreamCipher>(algo_spec, {"base", "openssl"});
147    }
148 
149 }
150