Python3 bindings for YACA
[platform/core/security/yaca.git] / python / yaca / __init__.py
1 #!/usr/bin/env python3
2
3 # Copyright (c) 2017-2018 Samsung Electronics Co., Ltd All Rights Reserved
4 #
5 # Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
6 #
7 # Licensed under the Apache License, Version 2.0 (the "License");
8 # you may not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
10 #
11 #     http://www.apache.org/licenses/LICENSE-2.0
12 #
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License
18
19
20 """
21 Python3 bindings for YACA.
22
23 Usage is almost the same as in the C API. All the functions that made
24 sense in Python were implemented. Memory allocations and functions for
25 getting length of the buffers were ommited as all those things are
26 handled automatically for both input and output.
27
28 All the parameters for strings/data expect python's bytes type. All
29 the parameters are named the same as in the C API and their meaning is
30 exactly the same.
31
32 The major exception being encrypt/decrypt update where second
33 parameter can have 2 meanings. This is only used for CCM_AAD. See
34 examples.
35
36 Some parameters now have default values for ease of use.
37
38 For details please refer to the C API doxygen documentation.
39
40 For examples see tests/examples in yaca.tests module.
41 """
42
43 import enum as _enum
44 import ctypes as _ctypes
45 import yaca.library
46 from yaca.error import *
47 del yaca.error
48
49 # Initialization
50
51 _lib = yaca.library.get_yaca()
52 del yaca.library
53
54
55 # Helpers
56
57 def _get_char_param_nullify_if_zero(param):
58     return None if len(param) == 0 else param
59
60
61 def _context_get_output_length(ctx, input_length):
62     output_length = _ctypes.c_size_t()
63     _lib.yaca_context_get_output_length(ctx,
64                                         input_length,
65                                         _ctypes.byref(output_length))
66     return output_length.value
67
68
69 # Types
70
71 class Context():
72     def __init__(self, ptr):
73         if not isinstance(ptr, _ctypes.c_void_p):
74             raise TypeError('Invalid type')
75         self._as_parameter_ = ptr
76
77     def __del__(self):
78         _lib.yaca_context_destroy(self._as_parameter_)
79
80
81 class Key():
82     def __init__(self, ptr):
83         if not isinstance(ptr, _ctypes.c_void_p):
84             raise TypeError('Invalid type')
85         self._as_parameter_ = ptr
86
87     def __del__(self):
88         _lib.yaca_key_destroy(self._as_parameter_)
89
90     def __repr__(self):
91         if self._as_parameter_.value is None:
92             return '<yaca.Key: KEY_NULL>'
93         return '<yaca.Key: ' + str(self.get_type()) + ', ' + \
94             str(self.get_bit_length()) + ' bits at ' + str(hex(id(self))) + '>'
95
96     def get_type(self):
97         return key_get_type(self)
98
99     def get_bit_length(self):
100         return key_get_bit_length(self)
101
102
103 KEY_NULL = Key(_ctypes.c_void_p())
104
105
106 # Enums
107
108 @_enum.unique
109 class KEY_FORMAT(_enum.Enum):
110     DEFAULT = 0
111     PKCS8 = 1
112
113
114 @_enum.unique
115 class KEY_FILE_FORMAT(_enum.Enum):
116     RAW = 0
117     BASE64 = 1
118     PEM = 2
119     DER = 3
120
121
122 @_enum.unique
123 class KEY_TYPE(_enum.Enum):
124     SYMMETRIC = 0
125     DES = 1
126     IV = 2
127     RSA_PUB = 3
128     RSA_PRIV = 4
129     DSA_PUB = 5
130     DSA_PRIV = 6
131     DH_PUB = 7
132     DH_PRIV = 8
133     EC_PUB = 9
134     EC_PRIV = 10
135     DSA_PARAMS = 11
136     DH_PARAMS = 12
137     EC_PARAMS = 13
138
139
140 class KEY_BIT_LENGTH(_enum.IntEnum):
141     IV_64BIT = 64
142     IV_128BIT = 128
143     UNSAFE_8BIT = 8
144     UNSAFE_40BIT = 40
145     UNSAFE_64BIT = 64
146     UNSAFE_80BIT = 80
147     UNSAFE_128BIT = 128
148     L192BIT = 192
149     L256BIT = 256
150     L512BIT = 512
151     L1024BIT = 1024
152     L2048BIT = 2048
153     L3072BIT = 3072
154     L4096BIT = 4096
155
156
157 @_enum.unique
158 class KEY_BIT_LENGTH_EC(_enum.IntEnum):
159     PRIME192V1 = 0x300000C0
160     PRIME256V1 = 0x30000100
161     SECP256K1 = 0x31200100
162     SECP384R1 = 0x31100180
163     SECP521R1 = 0x31100209
164
165
166 KEY_LENGTH_DH_GENERATOR_2 = 0x10000000
167 KEY_LENGTH_DH_GENERATOR_5 = 0x11000000
168
169
170 @_enum.unique
171 class KEY_BIT_LENGTH_DH_RFC(_enum.IntEnum):
172     L1024_160 = 0x20000400
173     L2048_224 = 0x21000800
174     L2048_256 = 0x22000800
175
176
177 @_enum.unique
178 class DIGEST_ALGORITHM(_enum.Enum):
179     MD5 = 0
180     SHA1 = 1
181     SHA224 = 2
182     SHA256 = 3
183     SHA384 = 4
184     SHA512 = 5
185
186
187 @_enum.unique
188 class ENCRYPT_ALGORITHM(_enum.Enum):
189     AES = 0
190     UNSAFE_DES = 1
191     UNSAFE_TRIPPLE_DES_2TDEA = 2
192     TRIPPLE_DES_3TDEA = 3
193     UNSAFE_RC2 = 4
194     UNSAFE_RC4 = 5
195     CAST5 = 6
196
197
198 @_enum.unique
199 class BLOCK_CIPHER_MODE(_enum.Enum):
200     NONE = 0
201     ECB = 1
202     CTR = 2
203     CBC = 3
204     GCM = 4
205     CFB = 5
206     CFB1 = 6
207     CFB8 = 7
208     OFB = 8
209     CCM = 9
210     WRAP = 10
211
212
213 @_enum.unique
214 class PROPERTY(_enum.Enum):
215     PADDING = 0
216     GCM_AAD = 1
217     GCM_TAG = 2
218     GCM_TAG_LEN = 3
219     CCM_AAD = 4
220     CCM_TAG = 5
221     CCM_TAG_LEN = 6
222     RC2_EFFECTIVE_KEY_BITS = 7
223
224
225 @_enum.unique
226 class PADDING(_enum.Enum):
227     NONE = 0
228     X931 = 1
229     PKCS1 = 2
230     PKCS1_PSS = 3
231     PKCS1_OAEP = 4
232     PKCS1_SSLV23 = 5
233     PKCS7 = 6
234
235
236 @_enum.unique
237 class KDF(_enum.Enum):
238     X942 = 0
239     X962 = 1
240
241
242 # Implementation crypto
243
244 def initialize():
245     """Initializes the library. Must be called before any other crypto
246     function. Should be called once in each thread that uses yaca."""
247     _lib.yaca_initialize()
248
249
250 def cleanup():
251     """Cleans up the library.
252     Must be called before exiting the thread that called yaca_initialize()."""
253     _lib.yaca_cleanup()
254
255
256 def memcmp(first, second, length):
257     """Safely compares first length bytes of two buffers."""
258     l = _ctypes.c_size_t(length)
259     return _lib.yaca_memcmp(first, second, l)
260
261
262 def random_bytes(length):
263     """Generates random data."""
264     data = _ctypes.create_string_buffer(length)
265     _lib.yaca_randomize_bytes(data, length)
266     return bytes(data)
267
268
269 def context_set_property(ctx, prop, prop_val):
270     """Sets the non-standard context properties.
271     Can only be called on an initialized context."""
272     if prop == PROPERTY.PADDING:
273         value = _ctypes.c_int(prop_val.value)
274         value_length = _ctypes.sizeof(value)
275         _lib.yaca_context_set_property(ctx,
276                                        prop.value,
277                                        _ctypes.byref(value),
278                                        value_length)
279     elif (prop == PROPERTY.GCM_AAD) or (prop == PROPERTY.CCM_AAD) or \
280          (prop == PROPERTY.GCM_TAG) or (prop == PROPERTY.CCM_TAG):
281         value = prop_val
282         value_length = len(prop_val)
283         _lib.yaca_context_set_property(ctx, prop.value,
284                                        value, value_length)
285     elif (prop == PROPERTY.GCM_TAG_LEN) or (prop == PROPERTY.CCM_TAG_LEN) or \
286          (prop == PROPERTY.RC2_EFFECTIVE_KEY_BITS):
287         value = _ctypes.c_size_t(prop_val)
288         value_length = _ctypes.sizeof(value)
289         _lib.yaca_context_set_property(
290             ctx, prop.value, _ctypes.byref(value), value_length)
291     else:
292         raise InvalidParameterError('Wrong property passed')
293
294
295 def context_get_property(ctx, prop):
296     """Returns the non-standard context properties.
297     Can only be called on an initialized context."""
298     value = _ctypes.c_void_p()
299     value_length = _ctypes.c_size_t()
300     _lib.yaca_context_get_property(ctx, prop.value, _ctypes.byref(value),
301                                    _ctypes.byref(value_length))
302     if prop == PROPERTY.PADDING:
303         value_cast = _ctypes.cast(value, _ctypes.POINTER(_ctypes.c_int))
304         value_proper = value_cast.contents.value
305         assert value_length.value == _ctypes.sizeof(value_cast.contents)
306     elif (prop == PROPERTY.GCM_AAD) or (prop == PROPERTY.CCM_AAD) or \
307          (prop == PROPERTY.GCM_TAG) or (prop == PROPERTY.CCM_TAG):
308         value_cast = _ctypes.cast(value, _ctypes.POINTER(_ctypes.c_char))
309         value_proper = value_cast[:value_length.value]
310         assert value_length.value == len(value_proper)
311     elif (prop == PROPERTY.GCM_TAG_LEN) or \
312          (prop == PROPERTY.CCM_TAG_LEN) or \
313          (prop == PROPERTY.RC2_EFFECTIVE_KEY_BITS):
314         value_cast = _ctypes.cast(value, _ctypes.POINTER(_ctypes.c_size_t))
315         value_proper = value_cast.contents.value
316         assert value_length.value == _ctypes.sizeof(value_cast.contents)
317     else:
318         raise InvalidParameterError('Wrong property passed')
319     _lib.yaca_free(value)
320     return value_proper
321
322
323 # Implementation key
324
325 def key_get_type(key):
326     """Gets key's type"""
327     key_type = _ctypes.c_int()
328     _lib.yaca_key_get_type(key, _ctypes.byref(key_type))
329     return KEY_TYPE(key_type.value)
330
331
332 def key_get_bit_length(key):
333     """Gets key's length (in bits)."""
334     key_bit_length = _ctypes.c_size_t()
335     _lib.yaca_key_get_bit_length(key, _ctypes.byref(key_bit_length))
336     return key_bit_length.value
337
338
339 def key_import(data, key_type=KEY_TYPE.SYMMETRIC, password=b''):
340     """Imports a key or key generation parameters."""
341     key = _ctypes.c_void_p()
342     _lib.yaca_key_import(key_type.value, _ctypes.c_char_p(password),
343                          data, len(data), _ctypes.byref(key))
344     return Key(key)
345
346
347 def key_export(key, key_file_fmt=KEY_FILE_FORMAT.BASE64,
348                key_fmt=KEY_FORMAT.DEFAULT, password=b''):
349     """Exports a key or key generation parameters to arbitrary format."""
350     data = _ctypes.POINTER(_ctypes.c_char)()
351     data_length = _ctypes.c_size_t()
352     _lib.yaca_key_export(key, key_fmt.value, key_file_fmt.value,
353                          _ctypes.c_char_p(password), _ctypes.byref(data),
354                          _ctypes.byref(data_length))
355     data_bytes = data[:data_length.value]
356     _lib.yaca_free(data)
357     return data_bytes
358
359
360 def key_generate(key_type=KEY_TYPE.SYMMETRIC,
361                  key_bit_length=KEY_BIT_LENGTH.L256BIT):
362     """Generates a secure key or key generation parameters
363     (or an Initialization Vector)."""
364     key = _ctypes.c_void_p()
365     _lib.yaca_key_generate(key_type.value, key_bit_length,
366                            _ctypes.byref(key))
367     return Key(key)
368
369
370 def key_generate_from_parameters(params):
371     """Generates a secure private asymmetric key from parameters."""
372     prv_key = _ctypes.c_void_p()
373     _lib.yaca_key_generate_from_parameters(params,
374                                            _ctypes.byref(prv_key))
375     return Key(prv_key)
376
377
378 def key_extract_public(prv_key):
379     """Extracts public key from a private one."""
380     pub_key = _ctypes.c_void_p()
381     _lib.yaca_key_extract_public(prv_key, _ctypes.byref(pub_key))
382     return Key(pub_key)
383
384
385 def key_extract_parameters(key):
386     """Extracts parameters from a private or a public key."""
387     params = _ctypes.c_void_p()
388     _lib.yaca_key_extract_parameters(key, _ctypes.byref(params))
389     return Key(params)
390
391
392 def key_derive_dh(prv_key, pub_key):
393     """Derives a shared secret using Diffie-Helmann or EC Diffie-Helmann
394     key exchange protocol."""
395     secret = _ctypes.POINTER(_ctypes.c_char)()
396     secret_length = _ctypes.c_size_t()
397     _lib.yaca_key_derive_dh(prv_key, pub_key, _ctypes.byref(secret),
398                             _ctypes.byref(secret_length))
399     secret_bytes = secret[:secret_length.value]
400     _lib.yaca_free(secret)
401     return secret_bytes
402
403
404 def key_derive_kdf(secret, key_material_length, info=b'',
405                    kdf=KDF.X942, digest_algo=DIGEST_ALGORITHM.SHA256):
406     """Derives a key material from shared secret."""
407     info_param = _get_char_param_nullify_if_zero(info)
408     key_material = _ctypes.POINTER(_ctypes.c_char)()
409     _lib.yaca_key_derive_kdf(kdf.value, digest_algo.value,
410                              secret, len(secret),
411                              info_param, len(info), key_material_length,
412                              _ctypes.byref(key_material))
413     key_material_bytes = key_material[:key_material_length]
414     _lib.yaca_free(key_material)
415     return key_material_bytes
416
417
418 def key_derive_pbkdf2(password, key_bit_length=KEY_BIT_LENGTH.L256BIT,
419                       salt=b'', digest_algo=DIGEST_ALGORITHM.SHA256,
420                       iterations=50000):
421     """Derives a key from user password (PKCS #5 a.k.a. pbkdf2 algorithm)."""
422     salt_param = _get_char_param_nullify_if_zero(salt)
423     key = _ctypes.c_void_p()
424     _lib.yaca_key_derive_pbkdf2(_ctypes.c_char_p(password), salt_param,
425                                 len(salt), iterations, digest_algo.value,
426                                 key_bit_length, _ctypes.byref(key))
427     return Key(key)
428
429
430 # Implementation simple
431
432 def simple_encrypt(sym_key, plaintext, encrypt_algo=ENCRYPT_ALGORITHM.AES,
433                    bcm=BLOCK_CIPHER_MODE.ECB, iv=KEY_NULL):
434     """Encrypts data using a symmetric cipher."""
435     plaintext_param = _get_char_param_nullify_if_zero(plaintext)
436     ciphertext = _ctypes.POINTER(_ctypes.c_char)()
437     ciphertext_length = _ctypes.c_size_t()
438     _lib.yaca_simple_encrypt(encrypt_algo.value, bcm.value, sym_key, iv,
439                              plaintext_param, len(plaintext),
440                              _ctypes.byref(ciphertext),
441                              _ctypes.byref(ciphertext_length))
442     ciphertext_bytes = ciphertext[:ciphertext_length.value]
443     _lib.yaca_free(ciphertext)
444     return ciphertext_bytes
445
446
447 def simple_decrypt(sym_key, ciphertext, encrypt_algo=ENCRYPT_ALGORITHM.AES,
448                    bcm=BLOCK_CIPHER_MODE.ECB, iv=KEY_NULL):
449     """Decrypts data using a symmetric cipher."""
450     ciphertext_param = _get_char_param_nullify_if_zero(ciphertext)
451     plaintext = _ctypes.POINTER(_ctypes.c_char)()
452     plaintext_length = _ctypes.c_size_t()
453     _lib.yaca_simple_decrypt(encrypt_algo.value, bcm.value, sym_key, iv,
454                              ciphertext_param, len(ciphertext),
455                              _ctypes.byref(plaintext),
456                              _ctypes.byref(plaintext_length))
457     plaintext_bytes = plaintext[:plaintext_length.value]
458     _lib.yaca_free(plaintext)
459     return plaintext_bytes
460
461
462 def simple_calculate_digest(message, digest_algo=DIGEST_ALGORITHM.SHA256):
463     """Calculates a digest of a message."""
464     message_param = _get_char_param_nullify_if_zero(message)
465     digest = _ctypes.POINTER(_ctypes.c_char)()
466     digest_length = _ctypes.c_size_t()
467     _lib.yaca_simple_calculate_digest(digest_algo.value, message_param,
468                                       len(message),
469                                       _ctypes.byref(digest),
470                                       _ctypes.byref(digest_length))
471     digest_bytes = digest[:digest_length.value]
472     _lib.yaca_free(digest)
473     return digest_bytes
474
475
476 def simple_calculate_signature(prv_key, message,
477                                digest_algo=DIGEST_ALGORITHM.SHA256):
478     """Creates a signature using asymmetric private key."""
479     message_param = _get_char_param_nullify_if_zero(message)
480     signature = _ctypes.POINTER(_ctypes.c_char)()
481     signature_length = _ctypes.c_size_t()
482     _lib.yaca_simple_calculate_signature(digest_algo.value, prv_key,
483                                          message_param, len(message),
484                                          _ctypes.byref(signature),
485                                          _ctypes.byref(signature_length))
486     signature_bytes = signature[:signature_length.value]
487     _lib.yaca_free(signature)
488     return signature_bytes
489
490
491 def simple_verify_signature(pub_key, message, signature,
492                             digest_algo=DIGEST_ALGORITHM.SHA256):
493     """Verifies a signature using asymmetric public key."""
494     return _lib.yaca_simple_verify_signature(digest_algo.value, pub_key,
495                                              message, len(message),
496                                              signature, len(signature))
497
498
499 def simple_calculate_hmac(sym_key, message,
500                           digest_algo=DIGEST_ALGORITHM.SHA256):
501     """Calculates a HMAC of given message using symmetric key."""
502     message_param = _get_char_param_nullify_if_zero(message)
503     mac = _ctypes.POINTER(_ctypes.c_char)()
504     mac_length = _ctypes.c_size_t()
505     _lib.yaca_simple_calculate_hmac(digest_algo.value, sym_key,
506                                     message_param, len(message),
507                                     _ctypes.byref(mac),
508                                     _ctypes.byref(mac_length))
509     mac_bytes = mac[:mac_length.value]
510     _lib.yaca_free(mac)
511     return mac_bytes
512
513
514 def simple_calculate_cmac(sym_key, message,
515                           encrypt_algo=ENCRYPT_ALGORITHM.AES):
516     """Calculates a CMAC of given message using symmetric key."""
517     message_param = _get_char_param_nullify_if_zero(message)
518     mac = _ctypes.POINTER(_ctypes.c_char)()
519     mac_length = _ctypes.c_size_t()
520     _lib.yaca_simple_calculate_cmac(encrypt_algo.value, sym_key,
521                                     message_param, len(message),
522                                     _ctypes.byref(mac),
523                                     _ctypes.byref(mac_length))
524     mac_bytes = mac[:mac_length.value]
525     _lib.yaca_free(mac)
526     return mac_bytes
527
528
529 # Implementation digest
530
531 def digest_initialize(digest_algo=DIGEST_ALGORITHM.SHA256):
532     """Initializes a digest context."""
533     ctx = _ctypes.c_void_p()
534     _lib.yaca_digest_initialize(_ctypes.byref(ctx), digest_algo.value)
535     return Context(ctx)
536
537
538 def digest_update(ctx, message):
539     """Feeds the message into the message digest algorithm."""
540     _lib.yaca_digest_update(ctx, message, len(message))
541
542
543 def digest_finalize(ctx):
544     """Calculates the final digest."""
545     output_length = _context_get_output_length(ctx, 0)
546     digest = _ctypes.create_string_buffer(output_length)
547     digest_length = _ctypes.c_size_t()
548     _lib.yaca_digest_finalize(ctx, digest, _ctypes.byref(digest_length))
549     return bytes(digest[:digest_length.value])
550
551
552 # Implementation encrypt
553
554 def encrypt_get_iv_bit_length(encrypt_algo, bcm, key_bin_length):
555     """Returns the recommended/default length of the Initialization Vector
556     for a given encryption configuration."""
557     iv_bit_length = _ctypes.c_size_t()
558     _lib.yaca_encrypt_get_iv_bit_length(encrypt_algo.value, bcm.value,
559                                         key_bin_length,
560                                         _ctypes.byref(iv_bit_length))
561     return iv_bit_length.value
562
563
564 def encrypt_initialize(sym_key, encrypt_algo=ENCRYPT_ALGORITHM.AES,
565                        bcm=BLOCK_CIPHER_MODE.ECB, iv=KEY_NULL):
566     """Initializes an encryption context."""
567     ctx = _ctypes.c_void_p()
568     _lib.yaca_encrypt_initialize(_ctypes.byref(ctx), encrypt_algo.value,
569                                  bcm.value, sym_key, iv)
570     return Context(ctx)
571
572
573 def encrypt_update(ctx, plaintext):
574     """Encrypts chunk of the data.
575     Alternatively plaintext can be the total length of the input (int).
576     This is used for CCM_AAD."""
577     if isinstance(plaintext, int):  # the case of using AAD in CCM
578         _lib.yaca_encrypt_update(ctx, None, plaintext, None,
579                                  _ctypes.byref(_ctypes.c_size_t()))
580         return
581
582     output_length = _context_get_output_length(ctx, len(plaintext))
583     ciphertext = _ctypes.create_string_buffer(output_length)
584     ciphertext_length = _ctypes.c_size_t()
585     _lib.yaca_encrypt_update(ctx, plaintext, len(plaintext),
586                              ciphertext, _ctypes.byref(ciphertext_length))
587     return bytes(ciphertext[:ciphertext_length.value])
588
589
590 def encrypt_finalize(ctx):
591     """Encrypts the final chunk of the data."""
592     output_length = _context_get_output_length(ctx, 0)
593     ciphertext = _ctypes.create_string_buffer(output_length)
594     ciphertext_length = _ctypes.c_size_t()
595     _lib.yaca_encrypt_finalize(ctx, ciphertext,
596                                _ctypes.byref(ciphertext_length))
597     return bytes(ciphertext[:ciphertext_length.value])
598
599
600 def decrypt_initialize(sym_key, encrypt_algo=ENCRYPT_ALGORITHM.AES,
601                        bcm=BLOCK_CIPHER_MODE.ECB, iv=KEY_NULL):
602     """Initializes an decryption context."""
603     ctx = _ctypes.c_void_p()
604     _lib.yaca_decrypt_initialize(_ctypes.byref(ctx), encrypt_algo.value,
605                                  bcm.value, sym_key, iv)
606     return Context(ctx)
607
608
609 def decrypt_update(ctx, ciphertext):
610     """Decrypts chunk of the data.
611     Alternatively ciphertext can be the total length of the input (int).
612     This is used for CCM_AAD."""
613     if isinstance(ciphertext, int):  # the case of using AAD in CCM
614         _lib.yaca_decrypt_update(ctx, None, ciphertext, None,
615                                  _ctypes.byref(_ctypes.c_size_t()))
616         return
617
618     output_length = _context_get_output_length(ctx, len(ciphertext))
619     plaintext = _ctypes.create_string_buffer(output_length)
620     plaintext_length = _ctypes.c_size_t()
621     _lib.yaca_decrypt_update(ctx, ciphertext, len(ciphertext),
622                              plaintext, _ctypes.byref(plaintext_length))
623     return bytes(plaintext[:plaintext_length.value])
624
625
626 def decrypt_finalize(ctx):
627     """Encrypts the final chunk of the data."""
628     output_length = _context_get_output_length(ctx, 0)
629     plaintext = _ctypes.create_string_buffer(output_length)
630     plaintext_length = _ctypes.c_size_t()
631     _lib.yaca_decrypt_finalize(ctx, plaintext,
632                                _ctypes.byref(plaintext_length))
633     return bytes(plaintext[:plaintext_length.value])
634
635
636 # Implementation sign
637
638 def sign_initialize(prv_key, digest_algo=DIGEST_ALGORITHM.SHA256):
639     """Initializes a signature context for asymmetric signatures."""
640     ctx = _ctypes.c_void_p()
641     _lib.yaca_sign_initialize(_ctypes.byref(ctx), digest_algo.value,
642                               prv_key)
643     return Context(ctx)
644
645
646 def sign_initialize_hmac(sym_key, digest_algo=DIGEST_ALGORITHM.SHA256):
647     """Initializes a signature context for HMAC."""
648     ctx = _ctypes.c_void_p()
649     _lib.yaca_sign_initialize_hmac(_ctypes.byref(ctx),
650                                    digest_algo.value, sym_key)
651     return Context(ctx)
652
653
654 def sign_initialize_cmac(sym_key, encrypt_algo=ENCRYPT_ALGORITHM.AES):
655     """Initializes a signature context for CMAC."""
656     ctx = _ctypes.c_void_p()
657     _lib.yaca_sign_initialize_cmac(_ctypes.byref(ctx),
658                                    encrypt_algo.value, sym_key)
659     return Context(ctx)
660
661
662 def sign_update(ctx, message):
663     """Feeds the message into the digital signature or MAC algorithm."""
664     _lib.yaca_sign_update(ctx, message, len(message))
665
666
667 def sign_finalize(ctx):
668     """Calculates the final signature or MAC."""
669     output_length = _context_get_output_length(ctx, 0)
670     signature = _ctypes.create_string_buffer(output_length)
671     signature_len = _ctypes.c_size_t()
672     _lib.yaca_sign_finalize(ctx, signature, _ctypes.byref(signature_len))
673     return bytes(signature[:signature_len.value])
674
675
676 def verify_initialize(pub_key, digest_algo=DIGEST_ALGORITHM.SHA256):
677     """Initializes a signature verification context for asymmetric signatures.
678     """
679     ctx = _ctypes.c_void_p()
680     _lib.yaca_verify_initialize(_ctypes.byref(ctx), digest_algo.value,
681                                 pub_key)
682     return Context(ctx)
683
684
685 def verify_update(ctx, message):
686     """Feeds the message into the digital signature verification algorithm."""
687     _lib.yaca_verify_update(ctx, message, len(message))
688
689
690 def verify_finalize(ctx, signature):
691     """Performs the verification."""
692     return _lib.yaca_verify_finalize(ctx, signature, len(signature))
693
694
695 # Implementation seal
696
697 def seal_initialize(pub_key, sym_key_bit_length=KEY_BIT_LENGTH.L256BIT,
698                     encrypt_algo=ENCRYPT_ALGORITHM.AES,
699                     bcm=BLOCK_CIPHER_MODE.ECB):
700     ctx = _ctypes.c_void_p()
701     sym_key = _ctypes.c_void_p()
702     iv = _ctypes.c_void_p()
703     _lib.yaca_seal_initialize(_ctypes.byref(ctx), pub_key,
704                               encrypt_algo.value, bcm.value,
705                               sym_key_bit_length, _ctypes.byref(sym_key),
706                               _ctypes.byref(iv))
707     return Context(ctx), Key(sym_key), Key(iv)
708
709
710 def seal_update(ctx, plaintext):
711     """Encrypts piece of the data."""
712     output_length = _context_get_output_length(ctx, len(plaintext))
713     ciphertext = _ctypes.create_string_buffer(output_length)
714     ciphertext_length = _ctypes.c_size_t()
715     _lib.yaca_seal_update(ctx, plaintext, len(plaintext),
716                           ciphertext, _ctypes.byref(ciphertext_length))
717     return bytes(ciphertext[:ciphertext_length.value])
718
719
720 def seal_finalize(ctx):
721     """Encrypts the final piece of the data."""
722     output_length = _context_get_output_length(ctx, 0)
723     ciphertext = _ctypes.create_string_buffer(output_length)
724     ciphertext_length = _ctypes.c_size_t()
725     _lib.yaca_seal_finalize(ctx, ciphertext,
726                             _ctypes.byref(ciphertext_length))
727     return bytes(ciphertext[:ciphertext_length.value])
728
729
730 def open_initialize(prv_key, sym_key, iv=KEY_NULL,
731                     sym_key_bit_length=KEY_BIT_LENGTH.L256BIT,
732                     encrypt_algo=ENCRYPT_ALGORITHM.AES,
733                     bcm=BLOCK_CIPHER_MODE.ECB):
734     """Initializes an asymmetric decryption context."""
735     ctx = _ctypes.c_void_p()
736     _lib.yaca_open_initialize(_ctypes.byref(ctx), prv_key,
737                               encrypt_algo.value, bcm.value,
738                               sym_key_bit_length, sym_key, iv)
739     return Context(ctx)
740
741
742 def open_update(ctx, ciphertext):
743     """Decrypts piece of the data."""
744     output_length = _context_get_output_length(ctx, len(ciphertext))
745     plaintext = _ctypes.create_string_buffer(output_length)
746     plaintext_length = _ctypes.c_size_t()
747     _lib.yaca_open_update(ctx, ciphertext, len(ciphertext),
748                           plaintext, _ctypes.byref(plaintext_length))
749     return bytes(plaintext[:plaintext_length.value])
750
751
752 def open_finalize(ctx):
753     """Decrypts last chunk of sealed message."""
754     output_length = _context_get_output_length(ctx, 0)
755     plaintext = _ctypes.create_string_buffer(output_length)
756     plaintext_length = _ctypes.c_size_t()
757     _lib.yaca_open_finalize(ctx, plaintext,
758                             _ctypes.byref(plaintext_length))
759     return bytes(plaintext[:plaintext_length.value])
760
761
762 # Implementation rsa
763
764 def rsa_public_encrypt(pub_key, plaintext, padding=PADDING.PKCS1):
765     """Encrypts data using a RSA public key (low-level encrypt equivalent)."""
766     ciphertext = _ctypes.POINTER(_ctypes.c_char)()
767     ciphertext_length = _ctypes.c_size_t()
768     plaintext_param = _get_char_param_nullify_if_zero(plaintext)
769     _lib.yaca_rsa_public_encrypt(padding.value, pub_key, plaintext_param,
770                                  len(plaintext),
771                                  _ctypes.byref(ciphertext),
772                                  _ctypes.byref(ciphertext_length))
773     ciphertext_bytes = ciphertext[:ciphertext_length.value]
774     _lib.yaca_free(ciphertext)
775     return ciphertext_bytes
776
777
778 def rsa_private_decrypt(prv_key, ciphertext, padding=PADDING.PKCS1):
779     """Decrypts data using a RSA private key (low-level decrypt equivalent)."""
780     plaintext = _ctypes.POINTER(_ctypes.c_char)()
781     plaintext_length = _ctypes.c_size_t()
782     ciphertext_param = _get_char_param_nullify_if_zero(ciphertext)
783     _lib.yaca_rsa_private_decrypt(padding.value, prv_key,
784                                   ciphertext_param, len(ciphertext),
785                                   _ctypes.byref(plaintext),
786                                   _ctypes.byref(plaintext_length))
787     plaintext_bytes = plaintext[:plaintext_length.value]
788     _lib.yaca_free(plaintext)
789     return plaintext_bytes
790
791
792 def rsa_private_encrypt(prv_key, plaintext, padding=PADDING.PKCS1):
793     """Encrypts data using a RSA private key (low-level sign equivalent)."""
794     ciphertext = _ctypes.POINTER(_ctypes.c_char)()
795     ciphertext_length = _ctypes.c_size_t()
796     plaintext_param = _get_char_param_nullify_if_zero(plaintext)
797     _lib.yaca_rsa_private_encrypt(padding.value, prv_key,
798                                   plaintext_param, len(plaintext),
799                                   _ctypes.byref(ciphertext),
800                                   _ctypes.byref(ciphertext_length))
801     ciphertext_bytes = ciphertext[:ciphertext_length.value]
802     _lib.yaca_free(ciphertext)
803     return ciphertext_bytes
804
805
806 def rsa_public_decrypt(pub_key, ciphertext, padding=PADDING.PKCS1):
807     """Decrypts data using a RSA public key (low-level verify equivalent)."""
808     plaintext = _ctypes.POINTER(_ctypes.c_char)()
809     plaintext_length = _ctypes.c_size_t()
810     ciphertext_param = _get_char_param_nullify_if_zero(ciphertext)
811     _lib.yaca_rsa_public_decrypt(padding.value, pub_key,
812                                  ciphertext_param, len(ciphertext),
813                                  _ctypes.byref(plaintext),
814                                  _ctypes.byref(plaintext_length))
815     plaintext_bytes = plaintext[:plaintext_length.value]
816     _lib.yaca_free(plaintext)
817     return plaintext_bytes