def setup_contexts(cls, mechanism, sym_key, nonce_iv): """ Set up contexts to do wrapping/unwrapping by symmetric keys. """ # Get a PK11 slot based on the cipher slot = nss.get_best_slot(mechanism) if sym_key is None: sym_key = slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism)) # If initialization vector was supplied use it, otherwise set it to # None if nonce_iv: iv_si = nss.SecItem(nonce_iv) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_data = cls.generate_nonce_iv(mechanism) if iv_data is not None: iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_param = None # Create an encoding context encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) # Create a decoding context decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) return encoding_ctx, decoding_ctx
def setup_contexts(self, mechanism, sym_key, iv): # Get a PK11 slot based on the cipher slot = nss.get_best_slot(mechanism) if sym_key is None: sym_key = slot.key_gen( mechanism, None, slot.get_best_key_length(mechanism)) # If initialization vector was supplied use it, otherwise set it to # None if iv: iv_data = nss.read_hex(iv) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_length = nss.get_iv_length(mechanism) if iv_length > 0: iv_data = nss.generate_random(iv_length) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_param = None # Create an encoding context encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) # Create a decoding context decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) return encoding_ctx, decoding_ctx
def generate_sym_key(): """ This Function generate Symmetric key and nonce data """ ## Initialize NSS Database opens temporary database and the internal PKCS #112 module nss.nss_init_nodb() ## Mechanism to be used for symmetric key mechanism = nss.CKM_DES_CBC_PAD # From the Soft token that we initialized get slot to generate symmetric key slot = nss.get_best_slot(mechanism) # Generate a symmetric key on the pk11 slot, The sym_key is of type PK11SymKey sym_key = slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism)) # Generate Nonce iv_length = nss.get_iv_length(mechanism) if iv_length > 0: # Generate Nonce iv_data = nss.generate_random(iv_length) # Pass this random data to NSS SecItem iv_si = nss.SecItem(iv_data) # Use the Data passed to SecItem for initialization Vector iv_param = nss.param_from_iv(mechanism, iv_si) # Random data is converted to hex pki_nonce = nss.data_to_hex(data=iv_data, separator=":") #print "generated %d bytes initialization vector: %s" % (iv_length, pki_nonce) # Create a Symmetric key Context using the Symmetric key, nonce The context should be # used for encrypt as well as decrypt encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) #return the symmetric key, nonce data, encoding context and decoding context to encrypt and # decrypt return sym_key, pki_nonce, encoding_ctx, decoding_ctx
def setup_contexts(self, mechanism, sym_key, iv): # Get a PK11 slot based on the cipher slot = nss.get_best_slot(mechanism) if sym_key is None: sym_key = slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism)) # If initialization vector was supplied use it, otherwise set it to # None if iv: iv_data = nss.read_hex(iv) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_length = nss.get_iv_length(mechanism) if iv_length > 0: iv_data = nss.generate_random(iv_length) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_param = None # Create an encoding context encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) # Create a decoding context decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) return encoding_ctx, decoding_ctx
def get_decryption_context(alg_id, sym_key, params_base64): # Build a decryption context using the same parameters used # when the encryption context was created. # Do NOT use the params returned by get_pbe_crypto_mechanism() # because the params often include an IV (Initialization Vector) # created with random data, therefore the params used in the # encryption context will not match the params needed for the # decryption context. Instead use the params used in the # encryption context. For interoperability reasons we exchange the # params as base64 encoded binary data. mechanism, params = alg_id.get_pbe_crypto_mechanism(sym_key) # Recreate the params used during encryption by initializing a # SecItem from base64 text data (indicated by ascii=True) params = nss.SecItem(params_base64, ascii=True) if not options.quiet: print(fmt_info("get_pbe_crypto_mechanism (decrypting) returned mechanism:", nss.key_mechanism_type_name(mechanism))) print() # Now we have enough information to create a decrypting context decrypt_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, params) return decrypt_ctx
def get_decryption_context(alg_id, sym_key, params_base64): # Build a decryption context using the same parameters used # when the encryption context was created. # Do NOT use the params returned by get_pbe_crypto_mechanism() # because the params often include an IV (Initialization Vector) # created with random data, therefore the params used in the # encryption context will not match the params needed for the # decryption context. Instead use the params used in the # encryption context. For interoperability reasons we exchange the # params as base64 encoded binary data. mechanism, params = alg_id.get_pbe_crypto_mechanism(sym_key) # Recreate the params used during encryption by initializing a # SecItem from base64 text data (indicated by ascii=True) params = nss.SecItem(params_base64, ascii=True) if not options.quiet: print( fmt_info( "get_pbe_crypto_mechanism (decrypting) returned mechanism:", nss.key_mechanism_type_name(mechanism), )) print() # Now we have enough information to create a decrypting context decrypt_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, params) return decrypt_ctx
def verify_sym_key(archived_key, archived_iv, algorithm, plain_text): """ This function verifies whether archived key is usable, Actually verifying this is senseless, reason any random data can be used for encryption, but still just for the heck of it. """ # Initialize NSS nss.nss_init_nodb() # Decode the base64 string to binary key = base64.decodestring(archived_data) # Currently we are assuming the mechanism to AES # Will need to add other mechanisms later, but # this is just an example. mechanism = nss.CKM_AES_CBC_PAD # Get the best pkcs11 slot slot = nss.get_best_slot(mechanism) # convert the binary to hex with separtor as : pki_key = nss.data_to_hex(data=key,separator=":") # create a nssSecItem object out of it. key_si = nss.SecItem(nss.read_hex(pki_key)) # Import the key to the slot sym_key = nss.import_sym_key(slot, mechanism, nss.PK11_OriginUnwrap, nss.CKA_ENCRYPT, key_si) # Same for the nonce data iv = base64.decodestring(archived_iv) iv_data = nss.data_to_hex(data=iv,separator=":") iv_si = nss.SecItem(nss.read_hex(iv_data)) iv_param = nss.param_from_iv(mechanism, iv_si) encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT,sym_key, iv_param) decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT,sym_key, iv_param) cipher_text = encoding_ctx.cipher_op(plain_text) cipher_text += encoding_ctx.digest_final() print cipher_text decoded_text = decoding_ctx.cipher_op(cipher_text) decoded_text += decoding_ctx.digest_final() print decoded_text
def setup_contexts(mechanism, key, iv): # Get a PK11 slot based on the cipher slot = nss.get_best_slot(mechanism) # If key was supplied use it, otherwise generate one if key: if verbose: print("using supplied key data") print("key:\n%s" % (key)) key_si = nss.SecItem(nss.read_hex(key)) sym_key = nss.import_sym_key(slot, mechanism, nss.PK11_OriginUnwrap, nss.CKA_ENCRYPT, key_si) else: if verbose: print("generating key data") sym_key = slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism)) # If initialization vector was supplied use it, otherwise set it to None if iv: if verbose: print("supplied iv:\n%s" % (iv)) iv_data = nss.read_hex(iv) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_length = nss.get_iv_length(mechanism) if iv_length > 0: iv_data = nss.generate_random(iv_length) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) if verbose: print("generated %d byte initialization vector: %s" % (iv_length, nss.data_to_hex(iv_data, separator=":"))) else: iv_param = None # Create an encoding context encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) # Create a decoding context decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) return encoding_ctx, decoding_ctx
def setup_contexts(mechanism, key, iv): # Get a PK11 slot based on the cipher slot = nss.get_best_slot(mechanism) # If key was supplied use it, otherwise generate one if key: if verbose: print "using supplied key data" print "key:\n%s" % (key) key_si = nss.SecItem(nss.read_hex(key)) sym_key = nss.import_sym_key(slot, mechanism, nss.PK11_OriginUnwrap, nss.CKA_ENCRYPT, key_si) else: if verbose: print "generating key data" sym_key = slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism)) # If initialization vector was supplied use it, otherwise set it to None if iv: if verbose: print "supplied iv:\n%s" % (iv) iv_data = nss.read_hex(iv) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_length = nss.get_iv_length(mechanism) if iv_length > 0: iv_data = nss.generate_random(iv_length) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) if verbose: print "generated %d byte initialization vector: %s" % \ (iv_length, nss.data_to_hex(iv_data, separator=":")) else: iv_param = None # Create an encoding context encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) # Create a decoding context decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) return encoding_ctx, decoding_ctx
def get_encryption_context(alg_id, sym_key): # In order for NSS to encrypt and decrypt data it needs an # encryption context to perform the operation in. The cipher used # for the encryption context is specified with a PK11 mechanism. # The cipher likely also needs additional parameters (i.e. an # Initialization Vector (IV) and possibly other values. # The get_pbe_crypto_mechanism() call computes the mechanism # and parameters for the PBE symmetric key we're using. # # Because the decryption context needs the same params used in # the encryption context we save the param block returned by # get_pbe_crypto_mechanism(). So that it can be passed to # create_context_by_sym_key() when creating the decryption context. # It's often the case the decryption is performed by a separate # process so in this example we illustrate exchanging the param # as base64 data. mechanism, params = alg_id.get_pbe_crypto_mechanism(sym_key) # Format the params binary data into a base64 string. The zero # passed for the chars_per_line parameter indicates we want the # base64 data as one single string as opposed to a list of wrapped # strings. params_base64 = params.to_base64(0) if not options.quiet: print( fmt_info( "get_pbe_crypto_mechanism (encrypting) returned mechanism:", nss.key_mechanism_type_name(mechanism), )) print( fmt_info("get_pbe_crypto_mechanism (encrypting) returned params:", params)) print() # Now we have enough information to create an encrypting context # and decrypting the data. encrypt_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, params) # Return the encrypting context and it's parameter block so that the # decryption context can use the same parameter block. return encrypt_ctx, params_base64
def __call__(self, element, mac=None): (mech, ivlen) = fetch(element, "./xenc:EncryptionMethod/@Algorithm", convertAlgorithm) data = fetch(element, "./xenc:CipherData/xenc:CipherValue/text()", base64.b64decode) # If a MAC is present, perform validation. if mac: tmp = self.__hmac.copy() tmp.update(data) if tmp.digest() != mac: raise ValidationError("MAC validation failed!") # Decrypt the data. slot = nss.get_best_slot(mech) key = nss.import_sym_key(slot, mech, nss.PK11_OriginUnwrap, nss.CKA_ENCRYPT, self.__key) iv = nss.param_from_iv(mech, nss.SecItem(data[0:ivlen//8])) ctx = nss.create_context_by_sym_key(mech, nss.CKA_DECRYPT, key, iv) out = ctx.cipher_op(data[ivlen // 8:]) out += ctx.digest_final() return out
def __call__(self, element, mac=None): (mech, ivlen) = fetch(element, "./xenc:EncryptionMethod/@Algorithm", convertAlgorithm) data = fetch(element, "./xenc:CipherData/xenc:CipherValue/text()", base64.b64decode) # If a MAC is present, perform validation. if mac: tmp = self.__hmac.copy() tmp.update(data) if tmp.digest() != mac: raise ValidationError("MAC validation failed!") # Decrypt the data. slot = nss.get_best_slot(mech) key = nss.import_sym_key(slot, mech, nss.PK11_OriginUnwrap, nss.CKA_ENCRYPT, self.__key) iv = nss.param_from_iv(mech, nss.SecItem(data[0:ivlen/8])) ctx = nss.create_context_by_sym_key(mech, nss.CKA_DECRYPT, key, iv) out = ctx.cipher_op(data[ivlen / 8:]) out += ctx.digest_final() return out
def get_encryption_context(alg_id, sym_key): # In order for NSS to encrypt and decrypt data it needs an # encryption context to perform the operation in. The cipher used # for the encryption context is specified with a PK11 mechanism. # The cipher likely also needs additional parameters (i.e. an # Initialization Vector (IV) and possibly other values. # The get_pbe_crypto_mechanism() call computes the mechanism # and parameters for the PBE symmetric key we're using. # # Because the decryption context needs the same params used in # the encryption context we save the param block returned by # get_pbe_crypto_mechanism(). So that it can be passed to # create_context_by_sym_key() when creating the decryption context. # It's often the case the decryption is performed by a separate # process so in this example we illustrate exchanging the param # as base64 data. mechanism, params = alg_id.get_pbe_crypto_mechanism(sym_key) # Format the params binary data into a base64 string. The zero # passed for the chars_per_line parameter indicates we want the # base64 data as one single string as opposed to a list of wrapped # strings. params_base64 = params.to_base64(0) if not options.quiet: print(fmt_info("get_pbe_crypto_mechanism (encrypting) returned mechanism:", nss.key_mechanism_type_name(mechanism))) print(fmt_info("get_pbe_crypto_mechanism (encrypting) returned params:", params)) print() # Now we have enough information to create an encrypting context # and decrypting the data. encrypt_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, params) # Return the encrypting context and it's parameter block so that the # decryption context can use the same parameter block. return encrypt_ctx, params_base64
def forward(self, *args, **options): data = options.get('data') input_file = options.get('in') password = options.get('password') password_file = options.get('password_file') override_password = options.pop('override_password', False) # don't send these parameters to server if 'data' in options: del options['data'] if 'in' in options: del options['in'] if 'password' in options: del options['password'] if 'password_file' in options: del options['password_file'] # get data if data and input_file: raise errors.MutuallyExclusiveError( reason=_('Input data specified multiple times')) elif data: if len(data) > MAX_VAULT_DATA_SIZE: raise errors.ValidationError(name="data", error=_( "Size of data exceeds the limit. Current vault data size " "limit is %(limit)d B") % {'limit': MAX_VAULT_DATA_SIZE}) elif input_file: try: stat = os.stat(input_file) except OSError as exc: raise errors.ValidationError(name="in", error=_( "Cannot read file '%(filename)s': %(exc)s") % {'filename': input_file, 'exc': exc.args[1]}) if stat.st_size > MAX_VAULT_DATA_SIZE: raise errors.ValidationError(name="in", error=_( "Size of data exceeds the limit. Current vault data size " "limit is %(limit)d B") % {'limit': MAX_VAULT_DATA_SIZE}) data = validated_read('in', input_file, mode='rb') else: data = '' if self.api.env.in_server: backend = self.api.Backend.ldap2 else: backend = self.api.Backend.rpcclient if not backend.isconnected(): backend.connect() # retrieve vault info vault = self.api.Command.vault_show(*args, **options)['result'] vault_type = vault['ipavaulttype'][0] if vault_type == u'standard': encrypted_key = None elif vault_type == u'symmetric': # get password if password and password_file: raise errors.MutuallyExclusiveError( reason=_('Password specified multiple times')) elif password: pass elif password_file: password = validated_read('password-file', password_file, encoding='utf-8') password = password.rstrip('\n') else: if override_password: password = get_new_password() else: password = get_existing_password() if not override_password: # verify password by retrieving existing data opts = options.copy() opts['password'] = password try: self.api.Command.vault_retrieve(*args, **opts) except errors.NotFound: pass salt = vault['ipavaultsalt'][0] # generate encryption key from vault password encryption_key = generate_symmetric_key(password, salt) # encrypt data with encryption key data = encrypt(data, symmetric_key=encryption_key) encrypted_key = None elif vault_type == u'asymmetric': public_key = vault['ipavaultpublickey'][0].encode('utf-8') # generate encryption key encryption_key = base64.b64encode(os.urandom(32)) # encrypt data with encryption key data = encrypt(data, symmetric_key=encryption_key) # encrypt encryption key with public key encrypted_key = encrypt(encryption_key, public_key=public_key) else: raise errors.ValidationError( name='vault_type', error=_('Invalid vault type')) # initialize NSS database nss.nss_init(api.env.nss_dir) # retrieve transport certificate config = self.api.Command.vaultconfig_show()['result'] transport_cert_der = config['transport_cert'] nss_transport_cert = nss.Certificate(transport_cert_der) # generate session key mechanism = nss.CKM_DES3_CBC_PAD slot = nss.get_best_slot(mechanism) key_length = slot.get_best_key_length(mechanism) session_key = slot.key_gen(mechanism, None, key_length) # wrap session key with transport certificate # pylint: disable=no-member public_key = nss_transport_cert.subject_public_key_info.public_key # pylint: enable=no-member wrapped_session_key = nss.pub_wrap_sym_key(mechanism, public_key, session_key) options['session_key'] = wrapped_session_key.data nonce_length = nss.get_iv_length(mechanism) nonce = nss.generate_random(nonce_length) options['nonce'] = nonce vault_data = {} vault_data[u'data'] = base64.b64encode(data).decode('utf-8') if encrypted_key: vault_data[u'encrypted_key'] = base64.b64encode(encrypted_key)\ .decode('utf-8') json_vault_data = json.dumps(vault_data) # wrap vault_data with session key iv_si = nss.SecItem(nonce) iv_param = nss.param_from_iv(mechanism, iv_si) encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, session_key, iv_param) wrapped_vault_data = encoding_ctx.cipher_op(json_vault_data)\ + encoding_ctx.digest_final() options['vault_data'] = wrapped_vault_data return self.api.Command.vault_archive_internal(*args, **options)
def forward(self, *args, **options): name = args[-1] data = options.get('data') input_file = options.get('in') password = options.get('password') password_file = options.get('password_file') # don't send these parameters to server if 'data' in options: del options['data'] if 'in' in options: del options['in'] if 'password' in options: del options['password'] if 'password_file' in options: del options['password_file'] # get data if data and input_file: raise errors.MutuallyExclusiveError( reason=_('Input data specified multiple times')) elif input_file: data = validated_read('in', input_file, mode='rb') elif not data: data = '' if self.api.env.in_server: backend = self.api.Backend.ldap2 else: backend = self.api.Backend.rpcclient if not backend.isconnected(): backend.connect(ccache=krbV.default_context().default_ccache()) # retrieve vault info vault = self.api.Command.vault_show(*args, **options)['result'] vault_type = vault['ipavaulttype'][0] if vault_type == u'standard': encrypted_key = None elif vault_type == u'symmetric': # get password if password and password_file: raise errors.MutuallyExclusiveError( reason=_('Password specified multiple times')) elif password: pass elif password_file: password = validated_read('password-file', password_file, encoding='utf-8') password = password.rstrip('\n') else: password = self.obj.get_existing_password() # verify password by retrieving existing data opts = options.copy() opts['password'] = password try: self.api.Command.vault_retrieve(*args, **opts) except errors.NotFound: pass salt = vault['ipavaultsalt'][0] # generate encryption key from vault password encryption_key = self.obj.generate_symmetric_key( password, salt) # encrypt data with encryption key data = self.obj.encrypt(data, symmetric_key=encryption_key) encrypted_key = None elif vault_type == u'asymmetric': public_key = vault['ipavaultpublickey'][0].encode('utf-8') # generate encryption key encryption_key = base64.b64encode(os.urandom(32)) # encrypt data with encryption key data = self.obj.encrypt(data, symmetric_key=encryption_key) # encrypt encryption key with public key encrypted_key = self.obj.encrypt( encryption_key, public_key=public_key) else: raise errors.ValidationError( name='vault_type', error=_('Invalid vault type')) # initialize NSS database current_dbdir = paths.IPA_NSSDB_DIR nss.nss_init(current_dbdir) # retrieve transport certificate config = self.api.Command.vaultconfig_show()['result'] transport_cert_der = config['transport_cert'] nss_transport_cert = nss.Certificate(transport_cert_der) # generate session key mechanism = nss.CKM_DES3_CBC_PAD slot = nss.get_best_slot(mechanism) key_length = slot.get_best_key_length(mechanism) session_key = slot.key_gen(mechanism, None, key_length) # wrap session key with transport certificate public_key = nss_transport_cert.subject_public_key_info.public_key wrapped_session_key = nss.pub_wrap_sym_key(mechanism, public_key, session_key) options['session_key'] = wrapped_session_key.data nonce_length = nss.get_iv_length(mechanism) nonce = nss.generate_random(nonce_length) options['nonce'] = nonce vault_data = {} vault_data[u'data'] = base64.b64encode(data).decode('utf-8') if encrypted_key: vault_data[u'encrypted_key'] = base64.b64encode(encrypted_key)\ .decode('utf-8') json_vault_data = json.dumps(vault_data) # wrap vault_data with session key iv_si = nss.SecItem(nonce) iv_param = nss.param_from_iv(mechanism, iv_si) encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, session_key, iv_param) wrapped_vault_data = encoding_ctx.cipher_op(json_vault_data)\ + encoding_ctx.digest_final() options['vault_data'] = wrapped_vault_data return self.api.Command.vault_archive_internal(*args, **options)
def forward(self, *args, **options): name = args[-1] output_file = options.get('out') password = options.get('password') password_file = options.get('password_file') private_key = options.get('private_key') private_key_file = options.get('private_key_file') # don't send these parameters to server if 'out' in options: del options['out'] if 'password' in options: del options['password'] if 'password_file' in options: del options['password_file'] if 'private_key' in options: del options['private_key'] if 'private_key_file' in options: del options['private_key_file'] if self.api.env.in_server: backend = self.api.Backend.ldap2 else: backend = self.api.Backend.rpcclient if not backend.isconnected(): backend.connect(ccache=krbV.default_context().default_ccache()) # retrieve vault info vault = self.api.Command.vault_show(*args, **options)['result'] vault_type = vault['ipavaulttype'][0] # initialize NSS database current_dbdir = paths.IPA_NSSDB_DIR nss.nss_init(current_dbdir) # retrieve transport certificate config = self.api.Command.vaultconfig_show()['result'] transport_cert_der = config['transport_cert'] nss_transport_cert = nss.Certificate(transport_cert_der) # generate session key mechanism = nss.CKM_DES3_CBC_PAD slot = nss.get_best_slot(mechanism) key_length = slot.get_best_key_length(mechanism) session_key = slot.key_gen(mechanism, None, key_length) # wrap session key with transport certificate public_key = nss_transport_cert.subject_public_key_info.public_key wrapped_session_key = nss.pub_wrap_sym_key(mechanism, public_key, session_key) # send retrieval request to server options['session_key'] = wrapped_session_key.data response = self.api.Command.vault_retrieve_internal(*args, **options) result = response['result'] nonce = result['nonce'] # unwrap data with session key wrapped_vault_data = result['vault_data'] iv_si = nss.SecItem(nonce) iv_param = nss.param_from_iv(mechanism, iv_si) decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, session_key, iv_param) json_vault_data = decoding_ctx.cipher_op(wrapped_vault_data)\ + decoding_ctx.digest_final() vault_data = json.loads(json_vault_data) data = base64.b64decode(vault_data[u'data'].encode('utf-8')) encrypted_key = None if 'encrypted_key' in vault_data: encrypted_key = base64.b64decode(vault_data[u'encrypted_key'] .encode('utf-8')) if vault_type == u'standard': pass elif vault_type == u'symmetric': salt = vault['ipavaultsalt'][0] # get encryption key from vault password if password and password_file: raise errors.MutuallyExclusiveError( reason=_('Password specified multiple times')) elif password: pass elif password_file: password = validated_read('password-file', password_file, encoding='utf-8') password = password.rstrip('\n') else: password = self.obj.get_existing_password() # generate encryption key from password encryption_key = self.obj.generate_symmetric_key(password, salt) # decrypt data with encryption key data = self.obj.decrypt(data, symmetric_key=encryption_key) elif vault_type == u'asymmetric': # get encryption key with vault private key if private_key and private_key_file: raise errors.MutuallyExclusiveError( reason=_('Private key specified multiple times')) elif private_key: pass elif private_key_file: private_key = validated_read('private-key-file', private_key_file, mode='rb') else: raise errors.ValidationError( name='private_key', error=_('Missing vault private key')) # decrypt encryption key with private key encryption_key = self.obj.decrypt( encrypted_key, private_key=private_key) # decrypt data with encryption key data = self.obj.decrypt(data, symmetric_key=encryption_key) else: raise errors.ValidationError( name='vault_type', error=_('Invalid vault type')) if output_file: with open(output_file, 'w') as f: f.write(data) else: response['result'] = {'data': data} return response
def forward(self, *args, **options): output_file = options.get('out') password = options.get('password') password_file = options.get('password_file') private_key = options.get('private_key') private_key_file = options.get('private_key_file') # don't send these parameters to server if 'out' in options: del options['out'] if 'password' in options: del options['password'] if 'password_file' in options: del options['password_file'] if 'private_key' in options: del options['private_key'] if 'private_key_file' in options: del options['private_key_file'] if self.api.env.in_server: backend = self.api.Backend.ldap2 else: backend = self.api.Backend.rpcclient if not backend.isconnected(): backend.connect() # retrieve vault info vault = self.api.Command.vault_show(*args, **options)['result'] vault_type = vault['ipavaulttype'][0] # initialize NSS database nss.nss_init(api.env.nss_dir) # retrieve transport certificate config = self.api.Command.vaultconfig_show()['result'] transport_cert_der = config['transport_cert'] nss_transport_cert = nss.Certificate(transport_cert_der) # generate session key mechanism = nss.CKM_DES3_CBC_PAD slot = nss.get_best_slot(mechanism) key_length = slot.get_best_key_length(mechanism) session_key = slot.key_gen(mechanism, None, key_length) # wrap session key with transport certificate # pylint: disable=no-member public_key = nss_transport_cert.subject_public_key_info.public_key # pylint: enable=no-member wrapped_session_key = nss.pub_wrap_sym_key(mechanism, public_key, session_key) # send retrieval request to server options['session_key'] = wrapped_session_key.data response = self.api.Command.vault_retrieve_internal(*args, **options) result = response['result'] nonce = result['nonce'] # unwrap data with session key wrapped_vault_data = result['vault_data'] iv_si = nss.SecItem(nonce) iv_param = nss.param_from_iv(mechanism, iv_si) decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, session_key, iv_param) json_vault_data = decoding_ctx.cipher_op(wrapped_vault_data)\ + decoding_ctx.digest_final() vault_data = json.loads(json_vault_data.decode('utf-8')) data = base64.b64decode(vault_data[u'data'].encode('utf-8')) encrypted_key = None if 'encrypted_key' in vault_data: encrypted_key = base64.b64decode(vault_data[u'encrypted_key'] .encode('utf-8')) if vault_type == u'standard': pass elif vault_type == u'symmetric': salt = vault['ipavaultsalt'][0] # get encryption key from vault password if password and password_file: raise errors.MutuallyExclusiveError( reason=_('Password specified multiple times')) elif password: pass elif password_file: password = validated_read('password-file', password_file, encoding='utf-8') password = password.rstrip('\n') else: password = get_existing_password() # generate encryption key from password encryption_key = generate_symmetric_key(password, salt) # decrypt data with encryption key data = decrypt(data, symmetric_key=encryption_key) elif vault_type == u'asymmetric': # get encryption key with vault private key if private_key and private_key_file: raise errors.MutuallyExclusiveError( reason=_('Private key specified multiple times')) elif private_key: pass elif private_key_file: private_key = validated_read('private-key-file', private_key_file, mode='rb') else: raise errors.ValidationError( name='private_key', error=_('Missing vault private key')) # decrypt encryption key with private key encryption_key = decrypt(encrypted_key, private_key=private_key) # decrypt data with encryption key data = decrypt(data, symmetric_key=encryption_key) else: raise errors.ValidationError( name='vault_type', error=_('Invalid vault type')) if output_file: with open(output_file, 'w') as f: f.write(data) else: response['result'] = {'data': data} return response