OpenSSL encryption error AES-256-CBC, Ruby "wrong end block length"
Using Ruby 1.8.6.
I am writing a basic server that echo the encrypted version sends a message from the client to inquire about the symmetric encryption implementation in Ruby. The program is designed to accept a socket connection, exchange a secret key, then encrypt the data it receives before sending it back to the client program. The client then decrypts the message using the shared secret, showing the echo'd message.
The problem I am facing is a return message that throws "wrong final block length (OpenSSL :: CipherError)". After looking at the issue, deleting decrypted << chiper.final
allows my client program to decrypt the message, but adds extra characters or bank spaces at the end. I know this is because the keyword final
removes the extra padding to allow 16-bit encryption / decryption of the CBC mode block, but I can't figure out how to get the job done correctly.
Here's a simplified server code (I know it's not secure, it isn't, this is just a tutorial application)
require 'socket'
require 'thread'
require 'openssl'
require 'digest/sha1'
class Server
@@static_id = 1
@connection_no
@port
@server
@aes_cipher
@key
def initialize(p)
#setting up server connections
puts "Starting server"
@port = p
puts "connections on port #{@port} will be accepted"
@server = TCPServer.open(@port)
#generate a secret key
puts "creating secret key..."
@aes_cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
@aes_cipher.encrypt
@key = @aes_cipher.random_key
@aes_cipher.key = @key
puts "key: #{@key}"
#start server
start_server
end
def start_server
loop{
Thread.new(@server.accept) do |client|
#connection and request
sock_domain, remote_port, remote_hostname, remote_ip = client.peeraddr
client_ip = remote_ip.to_s
@@static_id += 1
@connection_no = @@static_id
puts "\nConnection ##{@connection_no} client #{client_ip} accepted"
#send client secret key
client.puts @key
#receive data from client
data = client.gets
puts "received: #{data}"
# you will need to store these for later, in order to decrypt your data
iv = @aes_cipher.random_iv
@aes_cipher.iv = iv
puts "generated IV: #{iv}"
encrypted = @aes_cipher.update(data)
encrypted << @aes_cipher.final
puts "Encrypted Msg: #{encrypted}"
#send back IV and data
client.puts encrypted
client.puts iv
#close connections
client.close
end
}
end
end
And my client ...
require 'socket'
require 'thread'
require 'openssl'
require 'digest/sha1'
class aes_client
@port
@hostname
def initialize(p)
@hostname = 'localhost'
@port = p
connect
end
def connect
#establis connections
s = TCPSocket.new(@hostname, @port)
#get key on connection
key = s.gets
puts "Key to decrypt: #{key}"
#send data
data = $stdin.gets.chomp
s.puts data
#receive message and IV
message = s.gets
puts "Encrypted Message: #{message}"
iv = s.gets
puts "IV to decypt: #{iv}"
# now we create a sipher for decrypting
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
cipher.decrypt
cipher.key = key
cipher.iv = iv
# and decrypt it
decrypted = cipher.update(message)
#decrypted << cipher.final
puts "decrypted: #{decrypted}\n"
s.close
end
end
The client takes the information from the keyboard and sends it to the server before waiting for an encrypted message in response. As said, I can't think of waiting for it to decrypted << cipher.final
work correctly or successfully removing the extra addition from the echo'd message.
Any help would be greatly appreciated. Thank you.
source to share
puts
and gets
work with strings, and the ciphertext is binary. So you're in trouble if you're just expecting a string and then a newline in time gets
(especially if you try to decode the final newline as well, this is probably causing the error).
Instead, you could base 64 encode the ciphertext and IV (separately) first. Then gets.chomp
, decode and then decode the message.
If you're just a chomp
newline, then your encryption / decryption will probably work too ... as long as you don't accidentally enter a newline in the middle of the binary ciphertext.
So never forget that despite the name, the ciphertext is not actually text (for modern ciphers), it is a random binary string of bytes.
source to share