I'm a Ruby newbie and I need to implement a Geth-compatible key import/export in Ruby.

I was looking at the Geth implementation in Go, as well as keythereum.

This is what I have:

    require "eth"
    require 'fileutils'
    require 'json'
    require 'openssl'
    require 'securerandom'
    require 'test/unit'
     
    class SimpleTest < Test::Unit::TestCase
     
      def test_create_keys
    
        # hardcoded password
        password = "password"
    
        # create new keypair using https://github.com/se3000/ruby-eth
    		keypair = Eth::Key.new
    
    		# key version
    		version = 3
    
    		# Generate key uuid v4
    		uuid = SecureRandom.uuid
    
    		# address
    		address = keypair.to_address
    
    		# more on aes-128-ctr:
    		# https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29
    		cipher_name = "aes-128-ctr"
    		cipher = OpenSSL::Cipher.new cipher_name
    
    		# iv "Initialization Vector"
    		iv = SecureRandom.random_bytes(16) #store this with the generated value
    
    		# Derive encryption key from password
    		# kdf = key derivation function, for password-based keys
    		digest_name = "sha256"
    		prf = "hmac-" + digest_name
    		digest = OpenSSL::Digest.new digest_name
    		key_length = 32
    		salt_length = 32
    		iterations = 65536
    		salt = SecureRandom.random_bytes(salt_length) #store this with the generated value
    		derived_key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_length, digest)
    
    		# Encrypt private key with key derived from password
    		cipher.encrypt
    		cipher.iv = iv
    		iv = cipher.random_iv
    		cipher.key = derived_key
    		encrypted = cipher.update([keypair.private_key.to_hex].pack("H*")) + cipher.final
    
    		# Generate mac
    		derived_key_hex = derived_key.unpack("H*")[0]
    		encrypted_hex = encrypted.unpack("H*")[0]
    		mac = Eth::Utils.keccak256(derived_key_hex[32, 64] + encrypted)
    
    
    		json = {
    			"address" => address,
    			"crypto" => {
    				"cipher" => cipher_name,
    				"ciphertext" => encrypted_hex,
    				"cipherparams" => {
    					"iv" => iv.unpack("H*")[0]
    				},
    				"mac" => mac.unpack("H*")[0],
    				"kdf" => "pbkdf2",
    				"kdfparams" => {
    					"c" => iterations,
    					"dklen" => key_length, 
    					"prf" => prf, 
    					"salt" => salt.unpack("H*")[0], 
    				}
    			}, 
    			"id": uuid,
    			"version": version
    		}
    
    		file_name = "UTC--" + Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.%LZ") + "--" + address
    
    		FileUtils.mkdir_p 'keystore'
    		File.open("keystore/" + file_name,"w") do |f|
    		 	f.write(json.to_json)
    		end
      end
     
    end

In Geth, I see my generated address, but I can't unlock the account with the password I have used. 

    > personal.listAccounts
    ["0xf31081983dcf4984304c14563f82ab29a630144d"]
    > personal.unlockAccount("0xf31081983dcf4984304c14563f82ab29a630144d")
    Unlock account 0xf31081983dcf4984304c14563f82ab29a630144d
    Passphrase:
    could not decrypt key with given passphrase

Something wrong in my implementation, but I can't find the issue.