Convert to/from integer from/to string (i2osp from PKCS#1)

504 views
Skip to first unread message

Robert Feldt

unread,
Mar 11, 2014, 6:37:35 AM3/11/14
to julia...@googlegroups.com
Implementing simple RSA crypto in pure Julia (not for actual sec-sensitive use) but for low-sec applications. But I have troubles with encoding strings as integers and back. The PKCS#1 crypto standard says that strings should be seen as 8-bit (octet) strings. I tried creating a Uint8[] with the byte values and converting to ASCIIString but that fails when the values are more than 7 bits. However, I cannot just convert to UTF8String instead since those might not be valid either. 

Ideas for how to do this cleanly? Current code below... Thanks!

# Convert a non-negative integer i into an octet string. 
function i2osp(x::Integer, len = nothing)
  if typeof(len) <: Integer && (x >= 256^len)
    throw("integer is too large")
  end

  if x < 0
    throw("integer is negative")
  end

  bytes = Uint8[]
  while x > 0
    b = uint8(x & 0xff)
    push!(bytes, b)
    x = x >>> 8
  end
  str = convert(ASCIIString, reverse(bytes)) # Fails if any byte value > 127

  if typeof(len) <: Integer && (length(str) < len)
    str = repeat("\0", len - str) * str
  end

  return str
end

Ivar Nesje

unread,
Mar 11, 2014, 10:17:04 AM3/11/14
to julia...@googlegroups.com
In Julia you should not use strings to encode binary data, as you have to do in C. Strings in Julia is just a wrapper around an `Array{Uint8,1}` with some extra validation. As you do not want the validation, you should probably just use the array directly.

Why do you think you need a String?

Ivar

Robert Feldt

unread,
Mar 11, 2014, 11:02:32 AM3/11/14
to julia...@googlegroups.com
At least I think I need a string (;)) since:

1. The input to a RSA encryption is typically a string to be encrypted. This string is converted to a large integer which is then encrypted. This large integer is then dumped to a string so that it can be transmitted, saved to file etc.

2. The PKCS standard/spec describes the i2sop function and what it needs to do (http://tools.ietf.org/html/rfc3447#section-4.1). I'd like to find a nice way to implement it in Julia... :)

I guess I could send around Uint8[] internally and then dump it out in a "transport string" (Base64?) when it needs to be saved and communicated over sockets...

Cheers,

Robert

andrew cooke

unread,
Mar 11, 2014, 11:10:53 AM3/11/14
to julia...@googlegroups.com

do these not do what you need (or form the basis for it)?

julia> convert(Vector{Uint8}, utf8("hello world"))
11-element Array{Uint8,1}:
 0x68
 0x65
 0x6c
 0x6c
 0x6f
 0x20
 0x77
 0x6f
 0x72
 0x6c
 0x64

julia> bytestring(convert(Vector{Uint8}, utf8("hello world")))
"hello world"

Robert Feldt

unread,
Mar 11, 2014, 11:16:44 AM3/11/14
to julia...@googlegroups.com
Thanks Andrew,

That is exactly the kind of obvious-in-retrospect type of solution I was hoping for. I can adapt this to my needs.

Cheers,

Robert

andrew cooke

unread,
Mar 11, 2014, 11:18:51 AM3/11/14
to julia...@googlegroups.com

no problem.  don't forget the padding!

andrew cooke

unread,
Mar 11, 2014, 11:21:00 AM3/11/14
to julia...@googlegroups.com

actually, it seems convert works both ways. 

julia> convert(UTF8String, [0x41,0x42])
"AB"

Robert Feldt

unread,
Mar 11, 2014, 11:22:48 AM3/11/14
to julia...@googlegroups.com
Yes, but the problem I had was rooted in:

julia> convert(UTF8String, Uint8[0x41,0x42, 128])
ERROR: invalid UTF-8 sequence
 in convert at utf8.jl:155

/Robert

andrew cooke

unread,
Mar 11, 2014, 11:32:50 AM3/11/14
to julia...@googlegroups.com

well that's because it's an invalid character sequence.

if it started as a valid utf8 string, you won't see that or unencoding.

if it wasn't a utf8 string originally then you have an encoding issue.

you implied earlier that you want to share the encoded data as a string.  you don't.  it's either binary, or you convert to a hex string.  not utf8.

andrew

andrew cooke

unread,
Mar 11, 2014, 11:33:58 AM3/11/14
to julia...@googlegroups.com

sorry, last line should be "share the ENCRYPTED data", otherwise what i wrote is awfully confusing.

Robert Feldt

unread,
Mar 11, 2014, 11:37:34 AM3/11/14
to julia...@googlegroups.com
Yes, I see where I went wrong now. I will base64 encode the uint8 array, pass that around and then reverse on the other side.

Sorry for the noise,

Robert

andrew cooke

unread,
Mar 11, 2014, 11:51:49 AM3/11/14
to julia...@googlegroups.com

no problem.  really don't forget the padding.  http://rdist.root.org/2009/10/06/why-rsa-encryption-padding-is-critical/

Avik Sengupta

unread,
Mar 11, 2014, 3:13:05 PM3/11/14
to julia...@googlegroups.com
Does this work? 

julia> a="abcdefgh"
"abcdefgh"

julia> reinterpret(Int64, a.data)
1-element Array{Int64,1}:
 7523094288207667809

Robert Feldt

unread,
Mar 11, 2014, 4:05:21 PM3/11/14
to julia...@googlegroups.com
Seems useful and I did not know about it. Strings in my case can be longer than 64 bits though but this is a useful building block. Thanks!

Ivar Nesje

unread,
Mar 11, 2014, 4:18:14 PM3/11/14
to julia...@googlegroups.com
Reinterpret works for any length stings. See that the return type is Array{Int,1}.

Just be careful when using reinterpret because (I believe) you will get the native byte order (Litle endian/Big endian), and you should be careful to follow the specification of the algorithm/transport protocoll. 
Reply all
Reply to author
Forward
0 new messages