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
00351
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
00417
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
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))