security_policies.py
Go to the documentation of this file.
00001 from abc import ABCMeta, abstractmethod
00002 from opcua.ua import CryptographyNone, SecurityPolicy
00003 from opcua.ua import MessageSecurityMode
00004 from opcua.ua import UaError
00005 try:
00006     from opcua.crypto import uacrypto
00007     CRYPTOGRAPHY_AVAILABLE = True
00008 except ImportError:
00009     CRYPTOGRAPHY_AVAILABLE = False
00010 
00011 
00012 POLICY_NONE_URI = 'http://opcfoundation.org/UA/SecurityPolicy#None'
00013 
00014 
00015 def require_cryptography(obj):
00016     """
00017     Raise exception if cryptography module is not available.
00018     Call this function in constructors.
00019     """
00020     if not CRYPTOGRAPHY_AVAILABLE:
00021         raise UaError("Can't use {0}, cryptography module is not installed".format(obj.__class__.__name__))
00022 
00023 
00024 class Signer(object):
00025     """
00026     Abstract base class for cryptographic signature algorithm
00027     """
00028 
00029     __metaclass__ = ABCMeta
00030 
00031     @abstractmethod
00032     def signature_size(self):
00033         pass
00034 
00035     @abstractmethod
00036     def signature(self, data):
00037         pass
00038 
00039 
00040 class Verifier(object):
00041     """
00042     Abstract base class for cryptographic signature verification
00043     """
00044 
00045     __metaclass__ = ABCMeta
00046 
00047     @abstractmethod
00048     def signature_size(self):
00049         pass
00050 
00051     @abstractmethod
00052     def verify(self, data, signature):
00053         pass
00054 
00055 
00056 class Encryptor(object):
00057     """
00058     Abstract base class for encryption algorithm
00059     """
00060 
00061     __metaclass__ = ABCMeta
00062 
00063     @abstractmethod
00064     def plain_block_size(self):
00065         pass
00066 
00067     @abstractmethod
00068     def encrypted_block_size(self):
00069         pass
00070 
00071     @abstractmethod
00072     def encrypt(self, data):
00073         pass
00074 
00075 
00076 class Decryptor(object):
00077     """
00078     Abstract base class for decryption algorithm
00079     """
00080 
00081     __metaclass__ = ABCMeta
00082 
00083     @abstractmethod
00084     def plain_block_size(self):
00085         pass
00086 
00087     @abstractmethod
00088     def encrypted_block_size(self):
00089         pass
00090 
00091     @abstractmethod
00092     def decrypt(self, data):
00093         pass
00094 
00095 
00096 class Cryptography(CryptographyNone):
00097     """
00098     Security policy: Sign or SignAndEncrypt
00099     """
00100 
00101     def __init__(self, mode=MessageSecurityMode.Sign):
00102         self.Signer = None
00103         self.Verifier = None
00104         self.Encryptor = None
00105         self.Decryptor = None
00106         assert mode in (MessageSecurityMode.Sign,
00107                         MessageSecurityMode.SignAndEncrypt)
00108         self.is_encrypted = (mode == MessageSecurityMode.SignAndEncrypt)
00109 
00110     def plain_block_size(self):
00111         """
00112         Size of plain text block for block cipher.
00113         """
00114         if self.is_encrypted:
00115             return self.Encryptor.plain_block_size()
00116         return 1
00117 
00118     def encrypted_block_size(self):
00119         """
00120         Size of encrypted text block for block cipher.
00121         """
00122         if self.is_encrypted:
00123             return self.Encryptor.encrypted_block_size()
00124         return 1
00125 
00126     def padding(self, size):
00127         """
00128         Create padding for a block of given size.
00129         plain_size = size + len(padding) + signature_size()
00130         plain_size = N * plain_block_size()
00131         """
00132         if not self.is_encrypted:
00133             return b''
00134         block_size = self.Encryptor.plain_block_size()
00135         rem = (size + self.signature_size() + 1) % block_size
00136         if rem != 0:
00137             rem = block_size - rem
00138         return bytes(bytearray([rem])) * (rem + 1)
00139 
00140     def min_padding_size(self):
00141         if self.is_encrypted:
00142             return 1
00143         return 0
00144 
00145     def signature_size(self):
00146         return self.Signer.signature_size()
00147 
00148     def signature(self, data):
00149         return self.Signer.signature(data)
00150 
00151     def vsignature_size(self):
00152         return self.Verifier.signature_size()
00153 
00154     def verify(self, data, sig):
00155         self.Verifier.verify(data, sig)
00156 
00157     def encrypt(self, data):
00158         if self.is_encrypted:
00159             assert len(data) % self.Encryptor.plain_block_size() == 0
00160             return self.Encryptor.encrypt(data)
00161         return data
00162 
00163     def decrypt(self, data):
00164         if self.is_encrypted:
00165             return self.Decryptor.decrypt(data)
00166         return data
00167 
00168     def remove_padding(self, data):
00169         if self.is_encrypted:
00170             pad_size = bytearray(data[-1:])[0] + 1
00171             return data[:-pad_size]
00172         return data
00173 
00174 
00175 class SignerRsa(Signer):
00176 
00177     def __init__(self, client_pk):
00178         require_cryptography(self)
00179         self.client_pk = client_pk
00180         self.key_size = self.client_pk.key_size // 8
00181 
00182     def signature_size(self):
00183         return self.key_size
00184 
00185     def signature(self, data):
00186         return uacrypto.sign_sha1(self.client_pk, data)
00187 
00188 
00189 class VerifierRsa(Verifier):
00190 
00191     def __init__(self, server_cert):
00192         require_cryptography(self)
00193         self.server_cert = server_cert
00194         self.key_size = self.server_cert.public_key().key_size // 8
00195 
00196     def signature_size(self):
00197         return self.key_size
00198 
00199     def verify(self, data, signature):
00200         uacrypto.verify_sha1(self.server_cert, data, signature)
00201 
00202 
00203 class EncryptorRsa(Encryptor):
00204 
00205     def __init__(self, server_cert, enc_fn, padding_size):
00206         require_cryptography(self)
00207         self.server_cert = server_cert
00208         self.key_size = self.server_cert.public_key().key_size // 8
00209         self.encryptor = enc_fn
00210         self.padding_size = padding_size
00211 
00212     def plain_block_size(self):
00213         return self.key_size - self.padding_size
00214 
00215     def encrypted_block_size(self):
00216         return self.key_size
00217 
00218     def encrypt(self, data):
00219         encrypted = b''
00220         block_size = self.plain_block_size()
00221         for i in range(0, len(data), block_size):
00222             encrypted += self.encryptor(self.server_cert.public_key(),
00223                                         data[i: i + block_size])
00224         return encrypted
00225 
00226 
00227 class DecryptorRsa(Decryptor):
00228 
00229     def __init__(self, client_pk, dec_fn, padding_size):
00230         require_cryptography(self)
00231         self.client_pk = client_pk
00232         self.key_size = self.client_pk.key_size // 8
00233         self.decryptor = dec_fn
00234         self.padding_size = padding_size
00235 
00236     def plain_block_size(self):
00237         return self.key_size - self.padding_size
00238 
00239     def encrypted_block_size(self):
00240         return self.key_size
00241 
00242     def decrypt(self, data):
00243         decrypted = b''
00244         block_size = self.encrypted_block_size()
00245         for i in range(0, len(data), block_size):
00246             decrypted += self.decryptor(self.client_pk,
00247                                         data[i: i + block_size])
00248         return decrypted
00249 
00250 
00251 class SignerAesCbc(Signer):
00252 
00253     def __init__(self, key):
00254         require_cryptography(self)
00255         self.key = key
00256 
00257     def signature_size(self):
00258         return uacrypto.sha1_size()
00259 
00260     def signature(self, data):
00261         return uacrypto.hmac_sha1(self.key, data)
00262 
00263 
00264 class VerifierAesCbc(Verifier):
00265 
00266     def __init__(self, key):
00267         require_cryptography(self)
00268         self.key = key
00269 
00270     def signature_size(self):
00271         return uacrypto.sha1_size()
00272 
00273     def verify(self, data, signature):
00274         expected = uacrypto.hmac_sha1(self.key, data)
00275         if signature != expected:
00276             raise uacrypto.InvalidSignature
00277 
00278 
00279 class EncryptorAesCbc(Encryptor):
00280 
00281     def __init__(self, key, init_vec):
00282         require_cryptography(self)
00283         self.cipher = uacrypto.cipher_aes_cbc(key, init_vec)
00284 
00285     def plain_block_size(self):
00286         return self.cipher.algorithm.key_size // 8
00287 
00288     def encrypted_block_size(self):
00289         return self.cipher.algorithm.key_size // 8
00290 
00291     def encrypt(self, data):
00292         return uacrypto.cipher_encrypt(self.cipher, data)
00293 
00294 
00295 class DecryptorAesCbc(Decryptor):
00296 
00297     def __init__(self, key, init_vec):
00298         require_cryptography(self)
00299         self.cipher = uacrypto.cipher_aes_cbc(key, init_vec)
00300 
00301     def plain_block_size(self):
00302         return self.cipher.algorithm.key_size // 8
00303 
00304     def encrypted_block_size(self):
00305         return self.cipher.algorithm.key_size // 8
00306 
00307     def decrypt(self, data):
00308         return uacrypto.cipher_decrypt(self.cipher, data)
00309 
00310 
00311 class SecurityPolicyBasic128Rsa15(SecurityPolicy):
00312     """
00313     Security Basic 128Rsa15
00314     A suite of algorithms that uses RSA15 as Key-Wrap-algorithm
00315     and 128-Bit (16 bytes) for encryption algorithms.
00316     - SymmetricSignatureAlgorithm - HmacSha1
00317       (http://www.w3.org/2000/09/xmldsig#hmac-sha1)
00318     - SymmetricEncryptionAlgorithm - Aes128
00319       (http://www.w3.org/2001/04/xmlenc#aes128-cbc)
00320     - AsymmetricSignatureAlgorithm - RsaSha1
00321       (http://www.w3.org/2000/09/xmldsig#rsa-sha1)
00322     - AsymmetricKeyWrapAlgorithm - KwRsa15
00323       (http://www.w3.org/2001/04/xmlenc#rsa-1_5)
00324     - AsymmetricEncryptionAlgorithm - Rsa15
00325       (http://www.w3.org/2001/04/xmlenc#rsa-1_5)
00326     - KeyDerivationAlgorithm - PSha1
00327       (http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512/dk/p_sha1)
00328     - DerivedSignatureKeyLength - 128 (16 bytes)
00329     - MinAsymmetricKeyLength - 1024 (128 bytes)
00330     - MaxAsymmetricKeyLength - 2048 (256 bytes)
00331     - CertificateSignatureAlgorithm - Sha1
00332 
00333     If a certificate or any certificate in the chain is not signed with
00334     a hash that is Sha1 or stronger then the certificate shall be rejected.
00335     """
00336 
00337     URI = "http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15"
00338     signature_key_size = 16
00339     symmetric_key_size = 16
00340     AsymmetricEncryptionURI = "http://www.w3.org/2001/04/xmlenc#rsa-1_5"
00341 
00342     @staticmethod
00343     def encrypt_asymmetric(pubkey, data):
00344         return uacrypto.encrypt_rsa15(pubkey, data)
00345 
00346     def __init__(self, server_cert, client_cert, client_pk, mode):
00347         require_cryptography(self)
00348         if isinstance(server_cert, bytes):
00349             server_cert = uacrypto.x509_from_der(server_cert)
00350         # even in Sign mode we need to asymmetrically encrypt secrets
00351         # transmitted in OpenSecureChannel. So SignAndEncrypt here
00352         self.asymmetric_cryptography = Cryptography(
00353             MessageSecurityMode.SignAndEncrypt)
00354         self.asymmetric_cryptography.Signer = SignerRsa(client_pk)
00355         self.asymmetric_cryptography.Verifier = VerifierRsa(server_cert)
00356         self.asymmetric_cryptography.Encryptor = EncryptorRsa(
00357             server_cert, uacrypto.encrypt_rsa15, 11)
00358         self.asymmetric_cryptography.Decryptor = DecryptorRsa(
00359             client_pk, uacrypto.decrypt_rsa15, 11)
00360         self.symmetric_cryptography = Cryptography(mode)
00361         self.Mode = mode
00362         self.server_certificate = uacrypto.der_from_x509(server_cert)
00363         self.client_certificate = uacrypto.der_from_x509(client_cert)
00364 
00365     def make_symmetric_key(self, nonce1, nonce2):
00366         key_sizes = (self.signature_key_size, self.symmetric_key_size, 16)
00367 
00368         (sigkey, key, init_vec) = uacrypto.p_sha1(nonce2, nonce1, key_sizes)
00369         self.symmetric_cryptography.Signer = SignerAesCbc(sigkey)
00370         self.symmetric_cryptography.Encryptor = EncryptorAesCbc(key, init_vec)
00371 
00372         (sigkey, key, init_vec) = uacrypto.p_sha1(nonce1, nonce2, key_sizes)
00373         self.symmetric_cryptography.Verifier = VerifierAesCbc(sigkey)
00374         self.symmetric_cryptography.Decryptor = DecryptorAesCbc(key, init_vec)
00375 
00376 
00377 class SecurityPolicyBasic256(SecurityPolicy):
00378     """
00379     Security Basic 256
00380     A suite of algorithms that are for 256-Bit (32 bytes) encryption,
00381     algorithms include:
00382     - SymmetricSignatureAlgorithm - HmacSha1
00383       (http://www.w3.org/2000/09/xmldsig#hmac-sha1)
00384     - SymmetricEncryptionAlgorithm - Aes256
00385       (http://www.w3.org/2001/04/xmlenc#aes256-cbc)
00386     - AsymmetricSignatureAlgorithm - RsaSha1
00387       (http://www.w3.org/2000/09/xmldsig#rsa-sha1)
00388     - AsymmetricKeyWrapAlgorithm - KwRsaOaep
00389       (http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p)
00390     - AsymmetricEncryptionAlgorithm - RsaOaep
00391       (http://www.w3.org/2001/04/xmlenc#rsa-oaep)
00392     - KeyDerivationAlgorithm - PSha1
00393       (http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512/dk/p_sha1)
00394     - DerivedSignatureKeyLength - 192 (24 bytes)
00395     - MinAsymmetricKeyLength - 1024 (128 bytes)
00396     - MaxAsymmetricKeyLength - 2048 (256 bytes)
00397     - CertificateSignatureAlgorithm - Sha1
00398 
00399     If a certificate or any certificate in the chain is not signed with
00400     a hash that is Sha1 or stronger then the certificate shall be rejected.
00401     """
00402 
00403     URI = "http://opcfoundation.org/UA/SecurityPolicy#Basic256"
00404     signature_key_size = 24
00405     symmetric_key_size = 32
00406     AsymmetricEncryptionURI = "http://www.w3.org/2001/04/xmlenc#rsa-oaep"
00407 
00408     @staticmethod
00409     def encrypt_asymmetric(pubkey, data):
00410         return uacrypto.encrypt_rsa_oaep(pubkey, data)
00411 
00412     def __init__(self, server_cert, client_cert, client_pk, mode):
00413         require_cryptography(self)
00414         if isinstance(server_cert, bytes):
00415             server_cert = uacrypto.x509_from_der(server_cert)
00416         # even in Sign mode we need to asymmetrically encrypt secrets
00417         # transmitted in OpenSecureChannel. So SignAndEncrypt here
00418         self.asymmetric_cryptography = Cryptography(
00419             MessageSecurityMode.SignAndEncrypt)
00420         self.asymmetric_cryptography.Signer = SignerRsa(client_pk)
00421         self.asymmetric_cryptography.Verifier = VerifierRsa(server_cert)
00422         self.asymmetric_cryptography.Encryptor = EncryptorRsa(
00423             server_cert, uacrypto.encrypt_rsa_oaep, 42)
00424         self.asymmetric_cryptography.Decryptor = DecryptorRsa(
00425             client_pk, uacrypto.decrypt_rsa_oaep, 42)
00426         self.symmetric_cryptography = Cryptography(mode)
00427         self.Mode = mode
00428         self.server_certificate = uacrypto.der_from_x509(server_cert)
00429         self.client_certificate = uacrypto.der_from_x509(client_cert)
00430 
00431     def make_symmetric_key(self, nonce1, nonce2):
00432         # specs part 6, 6.7.5
00433         key_sizes = (self.signature_key_size, self.symmetric_key_size, 16)
00434 
00435         (sigkey, key, init_vec) = uacrypto.p_sha1(nonce2, nonce1, key_sizes)
00436         self.symmetric_cryptography.Signer = SignerAesCbc(sigkey)
00437         self.symmetric_cryptography.Encryptor = EncryptorAesCbc(key, init_vec)
00438 
00439         (sigkey, key, init_vec) = uacrypto.p_sha1(nonce1, nonce2, key_sizes)
00440         self.symmetric_cryptography.Verifier = VerifierAesCbc(sigkey)
00441         self.symmetric_cryptography.Decryptor = DecryptorAesCbc(key, init_vec)
00442 
00443 
00444 def encrypt_asymmetric(pubkey, data, policy_uri):
00445     """
00446     Encrypt data with pubkey using an asymmetric algorithm.
00447     The algorithm is selected by policy_uri.
00448     Returns a tuple (encrypted_data, algorithm_uri)
00449     """
00450     for cls in [SecurityPolicyBasic256, SecurityPolicyBasic128Rsa15]:
00451         if policy_uri == cls.URI:
00452             return (cls.encrypt_asymmetric(pubkey, data),
00453                     cls.AsymmetricEncryptionURI)
00454     if not policy_uri or policy_uri == POLICY_NONE_URI:
00455         return (data, '')
00456     raise UaError("Unsupported security policy `{0}`".format(policy_uri))


ros_opcua_impl_python_opcua
Author(s): Denis Štogl , Daniel Draper
autogenerated on Sat Jun 8 2019 18:26:23