1 /**
2 * OpenSSL Engine
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.engine.openssl_engine;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_ENGINE_OPENSSL):
15 
16 import botan.engine.engine;
17 import botan.pubkey.pk_keys;
18 import botan.rng.rng;
19 import botan.block.block_cipher;
20 import botan.math.bigint.bigint;
21 import botan.utils.parsing;
22 import deimos.openssl.rc4;
23 import deimos.openssl.evp;
24 import deimos.openssl.bn;
25 import deimos.openssl.aes;
26 
27 static if (BOTAN_HAS_RSA)  import botan.pubkey.algo.rsa;
28 static if (BOTAN_HAS_DSA)  import botan.pubkey.algo.dsa;
29 static if (BOTAN_HAS_ECDSA) {
30     import botan.pubkey.algo.ecdsa;
31 }
32 static if (BOTAN_HAS_DIFFIE_HELLMAN) import botan.pubkey.algo.dh;
33 
34 /**
35 * OpenSSL Engine
36 */
37 final class OpenSSLEngine : Engine
38 {
39 public:
40     string providerName() const { return "openssl"; }
41 
42     KeyAgreement getKeyAgreementOp(in PrivateKey key, RandomNumberGenerator) const
43     {
44         static if (BOTAN_HAS_DIFFIE_HELLMAN) {
45             if (DHPrivateKey.algoName == key.algoName)
46                 return new OSSLDHKAOperation(key);
47         }
48         
49         return null;
50     }
51 
52     Signature getSignatureOp(in PrivateKey key, RandomNumberGenerator) const
53     {
54         static if (BOTAN_HAS_RSA) {
55             if (RSAPrivateKey.algoName == key.algoName)
56                 return new OSSLRSAPrivateOperation(key);
57         }
58         
59         static if (BOTAN_HAS_DSA) {
60             if (DSAPrivateKey.algoName == key.algoName)
61                 return new OSSLDSASignatureOperation(key);
62         }
63         
64 		return null;
65 	}
66 	
67 	Verification getVerifyOp(in PublicKey key, RandomNumberGenerator) const
68     {
69         static if (BOTAN_HAS_RSA) {
70             if (RSAPublicKey.algoName == key.algoName)
71                 return new OSSLRSAPublicOperation(key);
72         }
73         
74         static if (BOTAN_HAS_DSA) {
75             if (DSAPublicKey.algoName == key.algoName)
76                 return new OSSLDSAVerificationOperation(key);
77         }
78         
79 		return null;
80 	}
81 	
82 	Encryption getEncryptionOp(in PublicKey key, RandomNumberGenerator) const
83     {
84         static if (BOTAN_HAS_RSA) {
85             if (RSAPublicKey.algoName == key.algoName)
86                 return new OSSLRSAPublicOperation(key);
87         }
88         
89 		return null;
90 	}
91 	
92 	Decryption getDecryptionOp(in PrivateKey key, RandomNumberGenerator) const
93     {
94         static if (BOTAN_HAS_RSA) {
95             if (RSAPrivateKey.algoName == key.algoName)
96                 return new OSSLRSAPrivateOperation(key);
97         }
98         
99 		return null;
100 	}
101 	
102 	/*
103     * Return the OpenSSL-based modular exponentiator
104     */
105     ModularExponentiator modExp(const ref BigInt n, PowerMod.UsageHints) const
106     {
107         return new OpenSSLModularExponentiator(n);
108     }
109 
110 
111     /*
112     * Look for an algorithm with this name
113     */
114     BlockCipher findBlockCipher(in SCANToken request, AlgorithmFactory af) const
115     {
116         
117         static if (!BOTAN_HAS_OPENSSL_NO_SHA) {
118             /*
119             Using OpenSSL's AES causes crashes inside EVP on x86-64 with OpenSSL 0.9.8g
120             cause is unknown
121             */
122             //mixin(HANDLE_EVP_CIPHER!("AES-128", EVP_aes_128_ecb));
123             //mixin(HANDLE_EVP_CIPHER!("AES-192", EVP_aes_192_ecb));
124             //mixin(HANDLE_EVP_CIPHER!("AES-256", EVP_aes_256_ecb));
125         }
126 
127         static if (!BOTAN_HAS_OPENSSL_NO_DES) {
128             mixin(HANDLE_EVP_CIPHER!("DES", EVP_des_ecb));
129             mixin(HANDLE_EVP_CIPHER_KEYLEN!("TripleDES", EVP_des_ede3_ecb, 16, 24, 8));
130         }
131         
132         static if (!BOTAN_HAS_OPENSSL_NO_BF) {
133             mixin(HANDLE_EVP_CIPHER_KEYLEN!("Blowfish", EVP_bf_ecb, 1, 56, 1));
134         }
135         
136         static if (!BOTAN_HAS_OPENSSL_NO_CAST) {
137             mixin(HANDLE_EVP_CIPHER_KEYLEN!("Cast-128", EVP_cast5_ecb, 1, 16, 1));
138         }
139 
140         static if (!BOTAN_HAS_OPENSSL_NO_CAMELLIA) {
141             mixin(HANDLE_EVP_CIPHER!("Camellia-128", EVP_camellia_128_ecb));
142             mixin(HANDLE_EVP_CIPHER!("Camellia-192", EVP_camellia_192_ecb));
143             mixin(HANDLE_EVP_CIPHER!("Camellia-256", EVP_camellia_256_ecb));
144         }
145         
146         static if (!BOTAN_HAS_OPENSSL_NO_RC2) {
147             mixin(HANDLE_EVP_CIPHER_KEYLEN!("RC2", EVP_rc2_ecb, 1, 32, 1));
148         }
149         
150         static if (!BOTAN_HAS_OPENSSL_NO_RC5) {
151             /*
152             if (request.algoName == "RC5")
153                 if (request.argAsInteger(0, 12) == 12)
154                     return new EVP_BlockCipher(EVP_rc5_32_12_16_ecb,
155                                                "RC5(12)", 1, 32, 1);
156             */
157         }
158         
159         static if (!BOTAN_HAS_OPENSSL_NO_IDEA) {
160             // HANDLE_EVP_CIPHER!("IDEA", EVP_idea_ecb);
161         }
162         
163         static if (!BOTAN_HAS_OPENSSL_NO_SEED) {
164             mixin(HANDLE_EVP_CIPHER!("SEED", EVP_seed_ecb));
165         }
166         
167 		return null;
168 	}
169 	
170 	/**
171     * Look for an OpenSSL-supported stream cipher (RC4)
172     */
173     StreamCipher findStreamCipher(in SCANToken request,
174                                     AlgorithmFactory) const
175     {
176         if (request.algoName == "RC4")
177             return new RC4OpenSSL(request.argAsInteger(0, 0));
178         if (request.algoName == "RC4_drop")
179             return new RC4OpenSSL(768);
180         
181 		return null;
182 	}
183 	
184 	
185     /*
186     * Look for an algorithm with this name
187     */
188     HashFunction findHash(in SCANToken request,
189                            AlgorithmFactory af) const
190     {
191         static if (!BOTAN_HAS_OPENSSL_NO_SHA) {
192             if (request.algoName == "SHA-160")
193                 return new EVPHashFunction(EVP_sha1(), "SHA-160");
194         }
195         
196         static if (!BOTAN_HAS_OPENSSL_NO_SHA256) {
197             if (request.algoName == "SHA-224")
198                 return new EVPHashFunction(EVP_sha224(), "SHA-224");
199             if (request.algoName == "SHA-256")
200                 return new EVPHashFunction(EVP_sha256(), "SHA-256");
201         }
202         
203         static if (!BOTAN_HAS_OPENSSL_NO_SHA512) {
204             if (request.algoName == "SHA-384")
205                 return new EVPHashFunction(EVP_sha384(), "SHA-384");
206             if (request.algoName == "SHA-512")
207                 return new EVPHashFunction(EVP_sha512(), "SHA-512");
208         }
209         
210         static if (!BOTAN_HAS_OPENSSL_NO_MD4) {
211             if (request.algoName == "MD4")
212                 return new EVPHashFunction(EVP_md4(), "MD4");
213         }
214         
215         static if (!BOTAN_HAS_OPENSSL_NO_MD5) {
216             if (request.algoName == "MD5")
217                 return new EVPHashFunction(EVP_md5(), "MD5");
218         }
219         
220         static if (!BOTAN_HAS_OPENSSL_NO_RIPEMD) {
221             if (request.algoName == "RIPEMD-160")
222                 return new EVPHashFunction(EVP_ripemd160(), "RIPEMD-160");
223         }
224         
225 		return null;
226 	}
227 	MessageAuthenticationCode findMac(in SCANToken algo_spec, AlgorithmFactory af) const
228 	{
229 		return null;
230 	}
231 	
232 	PBKDF findPbkdf(in SCANToken algo_spec, AlgorithmFactory af) const
233 	{
234 		return null;
235 	}
236 	
237 	
238 	KeyedFilter getCipher(in string algo_spec, CipherDir dir, AlgorithmFactory af) const
239 	{
240 		return null;
241 	}
242 }
243 
244 package:
245 
246 /*
247 * OpenSSL Modular Exponentiator
248 */
249 final class OpenSSLModularExponentiator : ModularExponentiator
250 {
251 public:
252     void setBase(const ref BigInt b) { m_base = OSSL_BN(b); }
253     
254     void setExponent(const ref BigInt e) { m_exp = OSSL_BN(e); }
255     
256     BigInt execute() const
257     {
258 		OSSL_BN r = OSSL_BN(true);
259         BN_mod_exp(r.ptr(), m_base.ptr(), m_exp.ptr(), m_mod.ptr(), m_ctx.getCtx());
260         return r.toBigint();
261     }
262     
263     ModularExponentiator copy() const
264     { 
265 		BigInt n = m_mod.toBigint();
266         OpenSSLModularExponentiator ret = new OpenSSLModularExponentiator(n);
267 		ret.m_exp = m_exp;
268 		ret.m_base = m_base;
269 
270 		return ret;
271     }
272     
273     this(const ref BigInt n) {
274 		m_ctx = new OSSL_BN_CTX;
275         m_mod = OSSL_BN(n);
276     }
277 private:
278 	this() {}
279     OSSL_BN m_base, m_exp, m_mod;
280     Unique!OSSL_BN_CTX m_ctx;
281 }
282 
283 /**
284 * Lightweight OpenSSL BN wrapper. For internal use only.
285 */
286 struct OSSL_BN
287 {
288 public:
289     /*
290     * OpenSSL to BigInt Conversions
291     */
292     BigInt toBigint() const
293     {
294         SecureVector!ubyte output = SecureVector!ubyte(bytes());
295         BN_bn2bin(m_bn, output.ptr);
296         return BigInt.decode(output);
297     }
298     
299     /*
300     * Export the BIGNUM as a bytestring
301     */
302     void encode(ubyte[] output) const
303     {
304         size_t length = output.length;
305         BN_bn2bin(m_bn, output.ptr + (length - bytes()));
306     }
307     
308     /*
309     * Return the number of significant bytes
310     */
311     size_t bytes() const
312     {
313         return BN_num_bytes(m_bn);
314     }
315     
316     
317     SecureVector!ubyte toBytes() const
318     { 
319         return BigInt.encodeLocked(toBigint()); 
320     }
321     
322     ref typeof(this) opAssign(in OSSL_BN other)
323     {
324 		if (m_bn)
325 			BN_copy(m_bn, other.m_bn);
326 		else m_bn = BN_dup(other.m_bn);
327 		return this;
328     }
329     
330     /*
331     * OSSL_BN Constructor
332     */
333     this(const ref BigInt input)
334     {
335         m_bn = BN_new();
336         SecureVector!ubyte encoding = BigInt.encodeLocked(input);
337         if (input != BigInt(0))
338             BN_bin2bn(encoding.ptr, cast(int)encoding.length, m_bn);
339 		auto ret = toBigint();
340     }
341     
342     /*
343     * OSSL_BN Constructor
344     */
345     this(const(ubyte)* input, size_t length)
346     {
347         m_bn = BN_new();
348         BN_bin2bn(input, cast(int)length, m_bn);
349     }
350     
351     this(OSSL_BN other)
352     {
353 		auto bn = m_bn;
354 		m_bn = other.m_bn;
355 		other.m_bn = bn;
356     }
357     
358     this(bool create) {
359 		m_bn = BN_new();
360 	}
361     
362     /*
363     * OSSL_BN Destructor
364     */
365     ~this() const
366     {
367 		if (m_bn)
368 	        BN_clear_free((cast()this).m_bn);
369     }
370         
371     BIGNUM* ptr() const { return (cast()this).m_bn; }
372 private:
373     BIGNUM* m_bn;
374 }
375 
376 /**
377 * Lightweight OpenSSL BN_CTX wrapper. For internal use only.
378 */
379 final class OSSL_BN_CTX
380 {
381 public:   	
382 	this(BN_CTX* ctx = null)
383     {
384 		m_ctx = BN_CTX_new();
385     }
386 
387     this(in OSSL_BN_CTX bn)
388     {
389 		m_ctx = BN_CTX_new();
390     }
391     
392     ~this()
393     {
394 		if (m_ctx)
395 	        BN_CTX_free(m_ctx);
396     }
397     
398     BN_CTX* getCtx() const { return (cast()this).m_ctx; }
399     
400 private:
401     BN_CTX* m_ctx;
402 }
403 
404 
405 package:
406 
407 /**
408 * RC4 as implemented by OpenSSL
409 */
410 final class RC4OpenSSL : StreamCipher
411 {
412 public:
413 	import botan.utils.mem_ops : clearMem;
414 	void clear() { clearMem(&m_state, 1); }
415     
416     /*
417     * Return the name of this type
418     */
419     @property string name() const
420     {
421 		if (m_SKIP == 0)        return "RC4";
422 		if (m_SKIP == 256)      return "MARK-4";
423         else                  return "RC4_skip(" ~ to!string(m_SKIP) ~ ")";
424     }
425     
426     StreamCipher clone() const { return new RC4OpenSSL(m_SKIP); }
427     
428     KeyLengthSpecification keySpec() const
429     {
430         return KeyLengthSpecification(1, 32);
431     }        
432     
433     this(size_t s = 0) { m_SKIP = s; clear(); }
434     
435     ~this() { clear(); }
436 	
437 	override bool validIvLength(size_t iv_len) const
438 	{ return (iv_len == 0); }
439 	
440 	override void setIv(const(ubyte)*, size_t iv_len) 
441 	{ 
442 		if (iv_len) 
443 			throw new InvalidArgument("The stream cipher " ~ name ~ " does not support resyncronization"); 
444 	}
445 
446 protected:
447     /*
448     * RC4 Encryption
449     */
450     void cipher(const(ubyte)* input, ubyte* output, size_t length)
451     {
452 		RC4(&m_state, cast(int)length, input, output);
453     }
454     
455     /*
456     * RC4 Key Schedule
457     */
458     override void keySchedule(const(ubyte)* key, size_t length)
459     {
460         RC4_set_key(&m_state, cast(int)length, key);
461         ubyte dummy = 0;
462         foreach (size_t i; 0 .. m_SKIP)
463             RC4(&m_state, 1, &dummy, &dummy);
464     }
465     
466     const size_t m_SKIP;
467     RC4_KEY m_state;
468 }
469 
470 /*
471 * EVP Block Cipher
472 */
473 final class EVPBlockCipher : BlockCipher, SymmetricAlgorithm
474 {
475 public:
476     /*
477     * Clear memory of sensitive data
478     */
479     void clear()
480     {
481         const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(&m_encrypt);
482         
483         EVP_CIPHER_CTX_cleanup(&m_encrypt);
484         EVP_CIPHER_CTX_cleanup(&m_decrypt);
485         EVP_CIPHER_CTX_init(&m_encrypt);
486         EVP_CIPHER_CTX_init(&m_decrypt);
487         EVP_EncryptInit_ex(&m_encrypt, algo, null, null, null);
488 		EVP_DecryptInit_ex(&m_decrypt, algo, null, null, null);
489 		EVP_CIPHER_CTX_set_padding(&m_encrypt, 0);
490 		EVP_CIPHER_CTX_set_padding(&m_decrypt, 0);
491     }
492     
493     @property string name() const { return m_cipher_name; }
494     /*
495     * Return a clone of this object
496     */
497     BlockCipher clone() const
498     {
499         return new EVPBlockCipher(EVP_CIPHER_CTX_cipher(&m_encrypt),
500                                    m_cipher_name,
501                                    m_cipher_key_spec.minimumKeylength(),
502                                    m_cipher_key_spec.maximumKeylength(),
503                                    m_cipher_key_spec.keylengthMultiple());
504     }
505     
506     @property size_t blockSize() const { return m_block_sz; }
507     /*
508     * EVP Block Cipher Constructor
509     */
510     this(const EVP_CIPHER* algo,
511          in string algo_name)
512     {
513         m_block_sz = EVP_CIPHER_block_size(algo);
514         m_cipher_key_spec = EVP_CIPHER_key_length(algo);
515         m_cipher_name = algo_name;
516         if (EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
517             throw new InvalidArgument("EVP_BlockCipher: Non-ECB EVP was passed in");
518         
519         EVP_CIPHER_CTX_init(&m_encrypt);
520         EVP_CIPHER_CTX_init(&m_decrypt);
521         
522         EVP_EncryptInit_ex(&m_encrypt, algo, null, null, null);
523         EVP_DecryptInit_ex(&m_decrypt, algo, null, null, null);
524         
525         EVP_CIPHER_CTX_set_padding(&m_encrypt, 0);
526         EVP_CIPHER_CTX_set_padding(&m_decrypt, 0);
527     }
528     
529     
530     /*
531     * EVP Block Cipher Constructor
532     */
533     this(const EVP_CIPHER* algo,
534          in string algo_name,
535          size_t key_min, size_t key_max,
536          size_t key_mod) 
537     {
538         m_block_sz = EVP_CIPHER_block_size(algo);
539         m_cipher_key_spec = KeyLengthSpecification(key_min, key_max, key_mod);
540         m_cipher_name = algo_name;
541         if (EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
542             throw new InvalidArgument("EVP_BlockCipher: Non-ECB EVP was passed in");
543         
544         EVP_CIPHER_CTX_init(&m_encrypt);
545         EVP_CIPHER_CTX_init(&m_decrypt);
546         
547         EVP_EncryptInit_ex(&m_encrypt, algo, null, null, null);
548 		EVP_DecryptInit_ex(&m_decrypt, algo, null, null, null);
549         
550         EVP_CIPHER_CTX_set_padding(&m_encrypt, 0);
551         EVP_CIPHER_CTX_set_padding(&m_decrypt, 0);
552     }
553     
554     
555     KeyLengthSpecification keySpec() const { return m_cipher_key_spec; }
556     
557     /*
558     * EVP Block Cipher Destructor
559     */
560     ~this()
561     {
562         EVP_CIPHER_CTX_cleanup(&m_encrypt);
563         EVP_CIPHER_CTX_cleanup(&m_decrypt);
564     }
565 
566 	override @property size_t parallelism() const { return 1; }
567 protected:
568     /*
569     * Encrypt a block
570     */
571     void encryptN(const(ubyte)* input, ubyte* output,
572                    size_t blocks)
573     {
574         int out_len = 0;
575         EVP_EncryptUpdate(&m_encrypt, output, &out_len, input, cast(int)(blocks * m_block_sz));
576     }
577     
578     /*
579     * Decrypt a block
580     */
581     void decryptN(const(ubyte)* input, ubyte* output,
582                    size_t blocks)
583     {
584         int out_len = 0;
585         EVP_DecryptUpdate(&m_decrypt, output, &out_len, input, cast(int)(blocks * m_block_sz));
586     }
587     
588     /*
589     * Set the key
590     */
591     override void keySchedule(const(ubyte)* key, size_t length)
592     {
593         SecureVector!ubyte full_key = SecureVector!ubyte(key[0 .. length]);
594         
595         if (m_cipher_name == "TripleDES" && length == 16)
596         {
597             full_key ~= key[0 .. 8];
598         }
599         else
600             if (EVP_CIPHER_CTX_set_key_length(&m_encrypt, cast(int)length) == 0 ||
601 				EVP_CIPHER_CTX_set_key_length(&m_decrypt, cast(int)length) == 0)
602                 throw new InvalidArgument("EVP_BlockCipher: Bad key length for " ~ m_cipher_name);
603         
604         if (m_cipher_name == "RC2")
605         {
606             EVP_CIPHER_CTX_ctrl(&m_encrypt, EVP_CTRL_SET_RC2_KEY_BITS, cast(int)length*8, null);
607             EVP_CIPHER_CTX_ctrl(&m_decrypt, EVP_CTRL_SET_RC2_KEY_BITS, cast(int)length*8, null);
608         }
609         
610         EVP_EncryptInit_ex(&m_encrypt, null, null, full_key.ptr, null);
611         EVP_DecryptInit_ex(&m_decrypt, null, null, full_key.ptr, null);
612     }
613     
614     size_t m_block_sz;
615     KeyLengthSpecification m_cipher_key_spec;
616     string m_cipher_name;
617     EVP_CIPHER_CTX m_encrypt, m_decrypt;
618 }
619 
620 
621 enum string HANDLE_EVP_CIPHER(string NAME, alias EVP) =
622     `if (request.algoName == "` ~ NAME ~ `" && request.argCount() == 0)
623         return new EVPBlockCipher(` ~ __traits(identifier, EVP) ~ `(), "` ~ NAME ~ `");`;
624 
625 enum string HANDLE_EVP_CIPHER_KEYLEN(string NAME, alias EVP, int MIN, int MAX, int MOD) =
626     `if (request.algoName == "` ~ NAME ~ `" && request.argCount() == 0)
627         return new EVPBlockCipher(` ~ __traits(identifier, EVP) ~ `(), "` ~ 
628         NAME ~ `", ` ~ MIN.stringof ~ `, ` ~ MAX.stringof ~ `, ` ~ MOD.stringof ~ `);`;
629 
630 /*
631 * EVP Hash Function
632 */
633 final class EVPHashFunction : HashFunction
634 {
635 public:
636     /*
637     * Clear memory of sensitive data
638     */
639     void clear()
640     {
641         const EVP_MD* algo = EVP_MD_CTX_md(&m_md);
642         EVP_DigestInit_ex(&m_md, algo, null);
643     }
644     
645     @property string name() const { return m_algo_name; }
646     /*
647     * Return a clone of this object
648     */
649     HashFunction clone() const
650     {
651         const EVP_MD* algo = EVP_MD_CTX_md(&m_md);
652         return new EVPHashFunction(algo, name);
653     }
654     
655     @property size_t outputLength() const
656     {
657         return EVP_MD_size(EVP_MD_CTX_md(&m_md));
658     }
659     
660     @property size_t hashBlockSize() const
661     {
662         return EVP_MD_block_size(EVP_MD_CTX_md(&m_md));
663     }
664     /*
665     * Create an EVP hash function
666     */
667     this(const EVP_MD* algo,
668          in string name)
669     {
670         m_algo_name = name;
671         EVP_MD_CTX_init(&m_md);
672         EVP_DigestInit_ex(&m_md, algo, null);
673     }
674     /*
675     * Destroy an EVP hash function
676     */
677     ~this()
678     {
679         EVP_MD_CTX_cleanup(&m_md);
680     }
681     
682 protected:
683     
684     /*
685     * Update an EVP Hash Calculation
686     */
687     override void addData(const(ubyte)* input, size_t length)
688     {
689         EVP_DigestUpdate(&m_md, input, length);
690     }
691     /*
692     * Finalize an EVP Hash Calculation
693     */
694     override void finalResult(ubyte* output)
695     {
696         EVP_DigestFinal_ex(&m_md, output, null);
697         const EVP_MD* algo = EVP_MD_CTX_md(&m_md);
698         EVP_DigestInit_ex(&m_md, algo, null);
699     }
700     
701     string m_algo_name;
702     EVP_MD_CTX m_md;
703 }
704 
705 
706 
707 package:
708 
709 static if (BOTAN_HAS_DIFFIE_HELLMAN) {
710     final class OSSLDHKAOperation : KeyAgreement
711     {
712     public:
713         this(in PrivateKey pkey) {
714             this(cast(DLSchemePrivateKey) pkey);
715         }
716 
717         this(in DHPrivateKey pkey) {
718             this(cast(DLSchemePrivateKey) pkey);
719         }
720 
721         this(in DLSchemePrivateKey dh) 
722         {
723             assert(dh.algoName == DHPublicKey.algoName);
724 			m_ctx = new OSSL_BN_CTX;
725             m_x = dh.getX();
726             m_p = dh.groupP();
727         }
728         
729         SecureVector!ubyte agree(const(ubyte)* w, size_t w_len)
730         {
731             OSSL_BN i = OSSL_BN(w, w_len);
732             OSSL_BN r = OSSL_BN(true);
733 
734             BN_mod_exp(r.ptr(), i.ptr(), m_x.ptr(), m_p.ptr(), m_ctx.getCtx());
735             return r.toBytes();
736         }
737         
738     private:
739         const OSSL_BN m_x, m_p;
740         Unique!OSSL_BN_CTX m_ctx;
741     }
742 }
743 
744 static if (BOTAN_HAS_DSA) {
745     
746     final class OSSLDSASignatureOperation : Signature
747     {
748     public:
749         this(in PrivateKey pkey) {
750             this(cast(DLSchemePrivateKey) pkey);
751         }
752 
753         this(in DSAPrivateKey pkey) {
754             this(cast(DLSchemePrivateKey) pkey);
755         }
756 
757         this(in DLSchemePrivateKey dsa) 
758         {
759             assert(dsa.algoName == DSAPublicKey.algoName);
760 			m_ctx = new OSSL_BN_CTX();
761             m_x = dsa.getX();
762             m_p = dsa.groupP();
763             m_q = dsa.groupQ();
764             m_g = dsa.groupG();
765             m_q_bits = dsa.groupQ().bits();
766         }
767         
768         size_t messageParts() const { return 2; }
769         size_t messagePartSize() const { return (m_q_bits + 7) / 8; }
770         size_t maxInputBits() const { return m_q_bits; }
771 
772         SecureVector!ubyte sign(const(ubyte)* msg, size_t msg_len, RandomNumberGenerator rng)
773         {
774             const size_t q_bytes = (m_q_bits + 7) / 8;
775             
776             rng.addEntropy(msg, msg_len);
777             
778             BigInt k_bn = BigInt(0);
779             do
780                 k_bn.randomize(rng, m_q_bits);
781             while (k_bn >= m_q.toBigint());
782             
783             OSSL_BN i = OSSL_BN(msg, msg_len);
784             OSSL_BN k = OSSL_BN(k_bn);
785             
786             OSSL_BN r = OSSL_BN(true);
787             BN_mod_exp(r.ptr(), m_g.ptr(), k.ptr(), m_p.ptr(), m_ctx.getCtx());
788             BN_nnmod(r.ptr(), r.ptr(), m_q.ptr(), m_ctx.getCtx());
789             
790             BN_mod_inverse(k.ptr(), k.ptr(), m_q.ptr(), m_ctx.getCtx());
791             
792             OSSL_BN s = OSSL_BN(true);
793             BN_mul(s.ptr(), m_x.ptr(), r.ptr(), m_ctx.getCtx());
794             BN_add(s.ptr(), s.ptr(), i.ptr());
795             BN_mod_mul(s.ptr(), s.ptr(), k.ptr(), m_q.ptr(), m_ctx.getCtx());
796             
797             if (BN_is_zero(r.ptr()) || BN_is_zero(s.ptr()))
798                 throw new InternalError("OpenSSL_DSA_Op::sign: r or s was zero");
799             
800             SecureVector!ubyte output = SecureVector!ubyte(2*q_bytes);
801             r.encode(output.ptr[0 .. q_bytes]);
802             s.encode(output.ptr[q_bytes .. output.length]);
803             return output;
804         }
805         
806     private:
807         const OSSL_BN m_x, m_p, m_q, m_g;
808         Unique!OSSL_BN_CTX m_ctx;
809         size_t m_q_bits;
810     }
811     
812     
813     final class OSSLDSAVerificationOperation : Verification
814     {
815     public:
816         this(in PublicKey pkey) {
817             this(cast(DLSchemePublicKey) pkey);
818         }
819 
820         this(in DSAPublicKey pkey) {
821 			this(cast(DLSchemePublicKey) pkey);
822 		}
823 
824         this(in DLSchemePublicKey dsa)
825         {
826             assert(dsa.algoName == DSAPublicKey.algoName);
827 			m_ctx = new OSSL_BN_CTX();
828             m_y = dsa.getY();
829             m_p = dsa.groupP();
830             m_q = dsa.groupQ();
831             m_g = dsa.groupG();
832             m_q_bits = dsa.groupQ().bits();
833         }
834         
835         size_t messageParts() const { return 2; }
836         size_t messagePartSize() const { return (m_q_bits + 7) / 8; }
837         size_t maxInputBits() const { return m_q_bits; }
838         
839         bool withRecovery() const { return false; }
840         
841 		override SecureVector!ubyte verifyMr(const(ubyte)*, size_t) { throw new InvalidState("Message recovery not supported"); }
842 
843         bool verify(const(ubyte)* msg, size_t msg_len,
844                     const(ubyte)* sig, size_t sig_len)
845         {
846             const size_t q_bytes = m_q.bytes();
847             
848             if (sig_len != 2*q_bytes || msg_len > q_bytes)
849                 return false;
850             
851             OSSL_BN r = OSSL_BN(sig, q_bytes);
852             OSSL_BN s = OSSL_BN(sig + q_bytes, q_bytes);
853             OSSL_BN i = OSSL_BN(msg, msg_len);
854             
855             if (BN_is_zero(r.ptr()) || BN_cmp(r.ptr(), m_q.ptr()) >= 0)
856                 return false;
857             if (BN_is_zero(s.ptr()) || BN_cmp(s.ptr(), m_q.ptr()) >= 0)
858                 return false;
859             
860             if (BN_mod_inverse(s.ptr(), s.ptr(), m_q.ptr(), m_ctx.getCtx()) is null)
861                 return false;
862             
863             OSSL_BN si = OSSL_BN(true);
864             BN_mod_mul(si.ptr(), s.ptr(), i.ptr(), m_q.ptr(), m_ctx.getCtx());
865             BN_mod_exp(si.ptr(), m_g.ptr(), si.ptr(), m_p.ptr(), m_ctx.getCtx());
866             
867             OSSL_BN sr = OSSL_BN(true);
868             BN_mod_mul(sr.ptr(), s.ptr(), r.ptr(), m_q.ptr(), m_ctx.getCtx());
869             BN_mod_exp(sr.ptr(), m_y.ptr(), sr.ptr(), m_p.ptr(), m_ctx.getCtx());
870             
871             BN_mod_mul(si.ptr(), si.ptr(), sr.ptr(), m_p.ptr(), m_ctx.getCtx());
872             BN_nnmod(si.ptr(), si.ptr(), m_q.ptr(), m_ctx.getCtx());
873             
874             if (BN_cmp(si.ptr(), r.ptr()) == 0)
875                 return true;
876             return false;
877         }
878         
879     private:
880         const OSSL_BN m_y, m_p, m_q, m_g;
881         Unique!OSSL_BN_CTX m_ctx;
882         size_t m_q_bits;
883     }
884     
885     
886     static if (BOTAN_HAS_RSA) {
887         
888         final class OSSLRSAPrivateOperation : Signature, Decryption
889         {
890         public:
891             this(in PrivateKey pkey) {
892                 this(cast(IFSchemePrivateKey) pkey);
893             }
894 
895             this(in RSAPrivateKey pkey) {
896 				this(cast(IFSchemePrivateKey) pkey);
897 			}
898 			
899             this(in IFSchemePrivateKey rsa)
900             {
901                 assert(rsa.algoName == RSAPublicKey.algoName);
902 				m_ctx = new OSSL_BN_CTX();
903 				m_mod = OSSL_BN(rsa.getN());
904 				m_q = OSSL_BN(rsa.getQ());
905 				m_c = OSSL_BN(rsa.getC());
906 				m_d1 = OSSL_BN(rsa.getD1());
907 				m_d2 = OSSL_BN(rsa.getD2());
908 				m_p = OSSL_BN(rsa.getP());
909 				m_n_bits = rsa.getN().bits();
910             }
911             
912             size_t maxInputBits() const { return (m_n_bits - 1); }
913             
914             SecureVector!ubyte sign(const(ubyte)* msg, size_t msg_len, RandomNumberGenerator)
915             {
916                 BigInt m = BigInt(msg, msg_len);
917                 BigInt x = privateOp(m);
918                 return BigInt.encode1363(x, (m_n_bits + 7) / 8);
919             }
920             
921             SecureVector!ubyte decrypt(const(ubyte)* msg, size_t msg_len)
922             {
923                 BigInt m = BigInt(msg, msg_len);
924 				auto dec = privateOp(m);
925                 return BigInt.encodeLocked(dec);
926             }
927 			final override size_t messagePartSize() const {
928 				return 0;
929 			}
930 			
931 			final override size_t messageParts() const {
932 				return 1;
933 			}
934 
935         private:
936             BigInt privateOp(const ref BigInt m) const
937             {
938 				OSSL_BN j1 = OSSL_BN(true);
939 				OSSL_BN j2 = OSSL_BN(true);
940                 OSSL_BN h = OSSL_BN(m);
941                 
942                 BN_mod_exp(j1.ptr(), h.ptr(), m_d1.ptr(), m_p.ptr(), m_ctx.getCtx());
943                 BN_mod_exp(j2.ptr(), h.ptr(), m_d2.ptr(), m_q.ptr(), m_ctx.getCtx());
944                 BN_sub(h.ptr(), j1.ptr(), j2.ptr());
945                 BN_mod_mul(h.ptr(), h.ptr(), m_c.ptr(), m_p.ptr(), m_ctx.getCtx());
946                 BN_mul(h.ptr(), h.ptr(), m_q.ptr(), m_ctx.getCtx());
947                 BN_add(h.ptr(), h.ptr(), j2.ptr());
948                 return h.toBigint();
949             }
950             
951             const OSSL_BN m_mod, m_p, m_q, m_d1, m_d2, m_c;
952             Unique!OSSL_BN_CTX m_ctx;
953             size_t m_n_bits;
954         }
955         
956         
957         final class OSSLRSAPublicOperation : Verification, Encryption
958         {
959         public:
960             this(in PublicKey pkey) {
961                 this(cast(IFSchemePublicKey) pkey);
962             }
963 
964             this(in RSAPublicKey pkey) {
965 				this(cast(IFSchemePublicKey) pkey);
966 			}
967 			
968             this(in IFSchemePublicKey rsa) 
969             {
970                 assert(rsa.algoName == RSAPublicKey.algoName);
971 				m_ctx = new OSSL_BN_CTX();
972                 m_n = &rsa.getN();
973                 m_e = rsa.getE();
974                 m_mod = rsa.getN();
975             }
976             
977             size_t maxInputBits() const { return (m_n.bits() - 1); }
978             bool withRecovery() const { return true; }
979             
980             SecureVector!ubyte encrypt(const(ubyte)* msg, size_t msg_len, RandomNumberGenerator)
981             {
982                 BigInt m = BigInt(msg, msg_len);
983                 return BigInt.encode1363(publicOp(m), m_n.bytes());
984             }
985             
986 			override bool verify(const(ubyte)*, size_t, const(ubyte)*, size_t)
987 			{
988 				throw new InvalidState("Message recovery required");
989 			}
990 
991             override SecureVector!ubyte verifyMr(const(ubyte)* msg, size_t msg_len)
992             {
993                 BigInt m = BigInt(msg, msg_len);
994                 return BigInt.encodeLocked(publicOp(m));
995             }
996 			final override size_t messagePartSize() const {
997 				return 0;
998 			}
999 			
1000 			final override size_t messageParts() const {
1001 				return 1;
1002 			}
1003 
1004         private:
1005             BigInt publicOp(const ref BigInt m) const
1006             {
1007                 if (m >= *m_n)
1008                     throw new InvalidArgument("RSA public op - input is too large");
1009                 
1010 				OSSL_BN m_bn = OSSL_BN(m);
1011 				OSSL_BN r = OSSL_BN(true);
1012                 BN_mod_exp(r.ptr(), m_bn.ptr(), m_e.ptr(), m_mod.ptr(), m_ctx.getCtx());
1013                 return r.toBigint();
1014             }
1015             
1016             const BigInt* m_n;
1017             const OSSL_BN m_e, m_mod;
1018             Unique!OSSL_BN_CTX m_ctx;
1019         }
1020         
1021     }
1022     
1023 }