How to convert UTF8 byte arrays to string in lua - utf-8

I have a table like this
table = {57,55,0,15,-25,139,130,-23,173,148,-24,136,158}
it is utf8 encoded byte array by php unpack function
unpack('C*',$str);
how can I convert it to utf-8 string I can read in lua?

Lua doesn't provide a direct function for turning a table of utf-8 bytes in numeric form into a utf-8 string literal. But it's easy enough to write something for this with the help of string.char:
function utf8_from(t)
local bytearr = {}
for _, v in ipairs(t) do
local utf8byte = v < 0 and (0xff + v + 1) or v
table.insert(bytearr, string.char(utf8byte))
end
return table.concat(bytearr)
end
Note that none of lua's standard functions or provided string facilities are utf-8 aware. If you try to print utf-8 encoded string returned from the above function you'll just see some funky symbols. If you need more extensive utf-8 support you'll want to check out some of the libraries mention from the lua wiki.

Here's a comprehensive solution that works for the UTF-8 character set restricted by RFC 3629:
do
local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
function utf8(decimal)
if decimal<128 then return string.char(decimal) end
local charbytes = {}
for bytes,vals in ipairs(bytemarkers) do
if decimal<=vals[1] then
for b=bytes+1,2,-1 do
local mod = decimal%64
decimal = (decimal-mod)/64
charbytes[b] = string.char(128+mod)
end
charbytes[1] = string.char(vals[2]+decimal)
break
end
end
return table.concat(charbytes)
end
end
function utf8frompoints(...)
local chars,arg={},{...}
for i,n in ipairs(arg) do chars[i]=utf8(arg[i]) end
return table.concat(chars)
end
print(utf8frompoints(72, 233, 108, 108, 246, 32, 8364, 8212))
--> Héllö €—

Related

Ruby openssl encryption with DES-CBC incorrect result

I am trying to replicate the encryption result from here in Ruby using OpenSSL: https://emvlab.org/descalc/?key=18074F7ADD44C903&iv=18074F7ADD44C903&input=4E5A56564F4C563230313641454E5300&mode=cbc&action=Encrypt&output=25C843BA5C043FFFB50F76E43A211F8D
Original string = "NZVVOLV2016AENS"
String converted to hexadecimal = "4e5a56564f4c563230313641454e53"
iv = "18074F7ADD44C903"
key = "18074F7ADD44C903"
Expected result = "9B699B4C59F1444E8D37806FA9D15F81"
Here is my ruby code:
require 'openssl'
require "base64"
include Base64
iv = "08074F7ADD44C903"
cipher = "08074F7ADD44C903"
def encode(string)
puts "Attempting encryption - Input: #{string}"
encrypt = OpenSSL::Cipher.new('DES-CBC')
encrypt.encrypt
encrypt.key = ["18074F7ADD44C903"].pack('H*') #.scan(/../).map{|b|b.hex}.pack('c*')
encrypt.iv = ["18074F7ADD44C903"].pack('H*')
result = encrypt.update(string) + encrypt.final
puts "Raw output: #{result.inspect}"
unpacked = result.unpack('H*')[0]
puts "Encrypted key is: #{unpacked}"
puts "Encrypted Should be: 9B699B4C59F1444E8D37806FA9D15F81"
return unpacked
end
res = encode("NZVVOLV2016AENS")
Output:
Encrypted key is: 9b699b4c59f1444ea723ab91e89c023a
Encrypted Should be: 9B699B4C59F1444E8D37806FA9D15F81
Interestingly, the first half of the result is correct, and the last 16 digits are incorrect.
The web site uses Zero padding by default, while the Ruby code uses PKCS#7 padding by default.
Ruby does not seem to support Zero padding, so disable the default padding and implement Zero padding yourself.
Zero padding pads to the next full block size with 0x00 values. The block size for DES is 8 bytes. If the last block of the plaintext is already filled, no padding is done:
def zeroPad(string, blocksize)
len = string.bytes.length
padLen = (blocksize - len % blocksize) % blocksize
string += "\0" * padLen
return string
end
In the encode() function (which should better be called encrypt() function) the following lines must be added before encryption:
encrypt.padding = 0 # disable PKCS#7 padding
string = zeroPad(string, 8) # enable Zero padding
The modified Ruby code then gives the same ciphertext as the web site.
Note that DES is insecure, also it' s insecure to use the key as IV (as well as a static IV). Furthermore, Zero padding is unreliable in contrast to PKCS#7 padding.

TreeView.insert throws UnicodeDecodeError

I'm trying to populate TreeView with data from os.listdir(path).
All is ok until I read a directory name with a non-utf character. In my case 0xf6 which is not utf8.
As I'm running on Windows the charset from os.listdir() is Windows-1252 or ANSI.
How can I solve this problem to achieve correct display in TreeView?
Here some of my code:
def fill_tree(treeview, node):
if treeview.set(node, "type") != 'directory':
return
path = treeview.set(node, "fullpath")
# Delete the possibly 'dummy' node present.
treeview.delete(*treeview.get_children(node))
parent = treeview.parent(node)
for p in os.listdir(path):
ptype = None
p = os.path.join(path, p)
if os.path.isdir(p):
ptype = 'directory'
fname = os.path.split(p)[1].decode('cp1252').encode('utf8')
if ptype == 'directory':
oid = treeview.insert(node, 'end', text=fname, values=[p, ptype])
treeview.insert(oid, 0, text='dummy')
Regards
Göran
The UnicodeDecodeError is due to passing byte strings when the function is expecting Unicode strings. Python 2 attempts to implicitly decode byte strings to Unicode. Use Unicode strings explicitly instead. os.listdir(unicode_path) will return Unicode string, for example os.listdir(u'.').

How to decoding IFC using Ruby

In Ruby, I'm reading an .ifc file to get some information, but I can't decode it. For example, the file content:
"'S\X2\00E9\X0\jour/Cuisine'"
should be:
"'Séjour/Cuisine'"
I'm trying to encode it with:
puts ifcFileLine.encode("Windows-1252")
puts ifcFileLine.encode("ISO-8859-1")
puts ifcFileLine.encode("ISO-8859-5")
puts ifcFileLine.encode("iso-8859-1").force_encoding("utf-8")'
But nothing gives me what I need.
I don't know anything about IFC, but based solely on the page Denis linked to and your example input, this works:
ESCAPE_SEQUENCE_EXPR = /\\X2\\(.*?)\\X0\\/
def decode_ifc(str)
str.gsub(ESCAPE_SEQUENCE_EXPR) do
$1.gsub(/..../) { $&.to_i(16).chr(Encoding::UTF_8) }
end
end
str = 'S\X2\00E9\X0\jour/Cuisine'
puts "Input:", str
puts "Output:", decode_ifc(str)
All this code does is replace every sequence of four characters (/..../) between the delimiters, which will each be a Unicode code point in hexadecimal, with the corresponding Unicode character.
Note that this code handles only this specific encoding. A quick glance at the implementation guide shows other encodings, including an \X4 directive for Unicode characters outside the Basic Multilingual Plane. This ought to get you started, though.
See it on eval.in: https://eval.in/776980
If someone is interested, I wrote here a Python Code that decode 3 of the IFC encodings : \X, \X2\ and \S\
import re
def decodeIfc(txt):
# In regex "\" is hard to manage in Python... I use this workaround
txt = txt.replace('\\', 'µµµ')
txt = re.sub('µµµX2µµµ([0-9A-F]{4,})+µµµX0µµµ', decodeIfcX2, txt)
txt = re.sub('µµµSµµµ(.)', decodeIfcS, txt)
txt = re.sub('µµµXµµµ([0-9A-F]{2})', decodeIfcX, txt)
txt = txt.replace('µµµ','\\')
return txt
def decodeIfcX2(match):
# X2 encodes characters with multiple of 4 hexadecimal numbers.
return ''.join(list(map(lambda x : chr(int(x,16)), re.findall('([0-9A-F]{4})',match.group(1)))))
def decodeIfcS(match):
return chr(ord(match.group(1))+128)
def decodeIfcX(match):
# Sometimes, IFC files were made with old Mac... wich use MacRoman encoding.
num = int(match.group(1), 16)
if (num <= 127) | (num >= 160):
return chr(num)
else:
return bytes.fromhex(match.group(1)).decode("macroman")

In ruby, how do you do a DES encryption with a ECB mode and PKCS7 padding

I am trying to convert some C# code into ruby. Here is a snippet of the C# code:
string Encrypt(string toEncrypt, string key) {
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
keyArray = UTF8Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
My biggest issue seems to be around getting the padding specification right.
Here is what I have so far...
des = OpenSSL::Cipher::Cipher.new('des-ecb')
des.encrypt # OpenSSL::PKCS7 has to passed in somewhere
des.key = '--The Key--'
update_value = des.update(val)
After running through all of the available OpenSSL ciphers and testing to see if any of the outputs resulted in the same encrypted string with no success, I then did the same thing, but this time passing in a padding integer (from 0 - 20), and iterated over all of the ciphers again.
This resulted in a success!
The final code:
def encrypt val
des = OpenSSL::Cipher::Cipher.new 'DES-EDE3'
des.encrypt
des.padding = 1
des.key = '--SecretKey--'
update_value = des.update(val)
up_final = update_value + des.final
Base64.encode64(up_final).gsub(/\n/, "")
end
The biggest thing to note is the I had to remove the newline characters, and had to put in a padding of 1.
I'm still confused on the padding...but, wanted to update everyone on what I found in case someone runs into this in the future
:Update: The padding didn't matter after all...if you take out that line it still encrypts the same as if you had any number in there...the big difference I was missing was taking out the newlines
Try 'des-ede3-ecb' or just '3des' as names instead. 'des-ecb' is unlikely to return a triple DES cipher.
PKCS#7 is normally the default for OpenSSL, so you may not have to specify it.
Make sure that your character-encoding (UTF-8, compatible with ASCII for values up to 7F) and encoding (base 64) matches as well.

Encrypting/decrypting 3DES in Ruby

I have a key.bin file which content is something along the lines of:
-12, 110, 93, 14, -48, ...
This is being used by a service to decrypt 3DES content, but I need to encrypt it via Ruby.
I've tried loads of scenarios with how to set the key and what to do with it, but to no avail as of yet:
Tried splitting the key by , and converting each number to hex, concatenating the hex values to make the key
Tried converting the number string to binary
Tried converting the resulting hex to binary
I assume what I need to do is something simple like:
des = OpenSSL::Cipher::Cipher.new('des3')
des.decrypt
des.key = mistery # this step is where i'm having problems at
final = des.update(encrypted) + des.final
Any ideas on what I should do with this key?
Key sample:
-62,-53,124,-110,37,-88,-48,31,-57,93,70,-101,44,69,-88,-57,-123,-99,118,-119,110,55,11,14
Data sample:
NEb2b9sYXgod6mTvaRv+MRsTJvIiTTI9VjnDGcxjxcN5qBH7FXvxYI6Oj16FeKKsoQvjAmdju2SQ
ifJqPJTl97xeEbjdwm+W8XJnWs99ku85EznVBhzQxI1H2jPiZIcrqIVCWdd/OQun7AjK4w2+5yb7
DPN2OiCIEOz2zK6skJrBw3oTEHpXrSEhydOYxqI+c5hC4z3k5nktN6WSVLIo8EAjwenHPMDxboWF
ET8R+QM5EznVBhzQxI1H2jPiZIcrqIVCWdd/OQun7AjK4w2+5yb7DPN2OiCIFqk4LRwEVq16jvKE
vjz6T4/G34kx6CEx/JdZ1LdvxC3xYQIcwS0wVnmtxorFm4q5QQFHzNKQ5chrGZzDkFzAogsZ2l2B
vcvlwgajNGHmxuVU83Ldn1e5rin7QqpjASqeDGFQHkiSbp4x6axVce2OGgfFpZdzCM7y6jLPpOlX
LOC/Bs1vTwMzcBNRB/Fo4nsX9i4It8Spm228XQNUpQe4i9QGe/4AyKIhHoM8DkXwPZ6rWp0W0UMe
keXjg41cED1JwjAAQSP3RYITB78bu+CEZKPOt2tQ2BvSw55mnFcvjIAYVQxCHliQ4PwgceHrnsZz
5aagC0QJ3oOKw9O0dlkVE3IM6KTBMcuZOZF19nCqxMFacQoDxjJY8tOJoN0Fe4Boz2FPyuggfLz9
yhljVJhxqOlTd8eA34Ex8SdC+5NDByAMumjzcPcXL8YVpSN85gytfd+skXhz3npmJ0dmZZOouu0Z
vMmlaCqw96Sy0L1mHLKbjqmZ/W57OBNRB/Fo4nsX9i4It8Spm228XQNUpQe4i9QGe/4AyKIhHoM8
DkXwPZ5tXdq1dRG6IaS51oNzFFlOoP3wTJuOTpj+zQOBMMOi4ENFyyEwYbG/qE+uY8rVwBOUHv9b
Yd9byvOZbnHDuf4oaWRZ+4K3s2NkEblDF9wU6Mb0ZqnLEJsypjrorH1cNIodIDu8nME1nD5bIDF6
XNrWC6pk6AV6eYQvNJw2QDz0RBD15fz/fAXCvbaCLDnhBKpLXrRbQdV+jxx2ipeC2ceMLLRFRPuR
B+ycYht65lWh4jNjoEsBXGFKiT0bSX6Lx/ZQD3twJWbML8ifRhw7SW0jOkUF+dAfXYNaD6nqA6Xq
TkcsDGaJsVq8wwCIWNh6tDRSw7ba4c391147kmnqEgXdKmmnEzUfHtpRw88C0/u0qj809hB4qB0B
lxj/87aDo4VOz9S4jjtk849CxtA/a9+532A4YlXjsPt/f0KZ2drAGEr1VSWzaLh/sMwP5tznmPaK
uozS6C74gMNdhtNMFz0HONcYecS0hg4lrdRyljROgzC33QoBIHbQXJrG0OXE3+81uhJwusEnFaD9
8Eybjk6YeNk3oxL3C5fx/xXgFmhcLLGdxRe/am0jqA1gV6MyQFUKtzdnNOUYpHkYXT9Ea7YYln4Q
D96Z9AI5EznVBhzQxI1H2jPiZIcrqIVCWdd/OQun7AjK4w2+5yb7DPN2OiCIFqk4LRwEVq16jvKE
vjz6T4/G34kx6CEx/JdZ1LdvxC3iEcYTrEH9kKhPrmPK1cATlB7/W2HfW8rzmW5xw7n+KGlkWfuC
t7NjZBG5QxfcFOjG9GapyxCbMqY66Kx9XDSKHSA7vJzBNZw+WyAxelza1guqZOgFenmElSgtUOo7
TEunuphaMIEQgo0udojG6dm2FtRmA4yntNCnCDzGTY72nrFBz3EZmVXGEm6X3Xd5Ito=
Got it working!
Here's how:
Decryption
def read_key(key_file)
File.read(key_file).split(',').map { |x| x.to_i }.pack('c*')
end
des = OpenSSL::Cipher::Cipher.new('des-ede3')
des.decrypt
des.key = read_key('key.bin')
result = des.update(decoded) + des.final
Encryption
def read_key(key_file)
File.read(key_file).split(',').map { |x| x.to_i }.pack('c*')
end
des2 = OpenSSL::Cipher::Cipher.new('des-ede3')
des2.encrypt
des2.key = read_key('key.bin')
result = des2.update(result) + des2.final
puts Base64.encode64(result)

Resources