Skip to content
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
OpenSSL
==========

fork of [OpenSSL](https://github.com/dirk/OpenSSL.jl)

convert for julia 0.4-


# how to use it

```julia
import OpenSSL

OpenSSL.init()
s = OpenSSL.Digest.digest("SHA512", "test")
m = OpenSSL.Digest.digest("MD5", "test")
OpenSSL.cleanup()
```


# see also

[AES256CBC](https://github.com/HatsuneMiku/AES256CBC.jl)

```julia
# AES256CBC encrypt/decrypt
using AES256CBC
# typealias UBytes Array{UInt8, 1}
plain = string2bytes("Message") # UBytes
passwd = string2bytes("Secret Passphrase") # UBytes
salt = genRandUBytes(8) # UBytes
(key32, iv16) = genKey32Iv16(passwd, salt) # (UBytes, UBytes)
encoded = encryptAES256CBC(key32, iv16, plain) # UBytes
decoded = decryptAES256CBC(key32, iv16, encoded) # UBytes
```


# status

[![Build Status _dev_aes256cbc](https://travis-ci.org/HatsuneMiku/OpenSSL.jl.svg?branch=_dev_aes256cbc)](https://travis-ci.org/HatsuneMiku/OpenSSL.jl)

[![Build Status master](https://travis-ci.org/HatsuneMiku/OpenSSL.jl.svg?branch=master)](https://travis-ci.org/HatsuneMiku/OpenSSL.jl)
1 change: 1 addition & 0 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
julia 0.4-
195 changes: 155 additions & 40 deletions src/OpenSSL.jl
Original file line number Diff line number Diff line change
@@ -1,54 +1,61 @@
# OpenSSL

VERSION >= v"0.4.0-dev+6521" && __precompile__()
module OpenSSL
import Base

const LIBCRYPTO = "libcrypto"


const LIBCRYPTO = @windows ? "libeay32" : "libcrypto"

function init()
# ccall((:OpenSSL_add_all_digests, OpenSSL.LIBCRYPTO), Void, ())
# ccall((:OpenSSL_add_all_ciphers, OpenSSL.LIBCRYPTO), Void, ())
# ccall((:OPENSSL_add_all_algorithms_conf, OpenSSL.LIBCRYPTO), Void, ())
ccall((:OPENSSL_add_all_algorithms_noconf, OpenSSL.LIBCRYPTO), Void, ())
# alias OpenSSL_add_all_algorithms :OPENSSL_add_all_algorithms_noconf
end

function cleanup()
ccall((:EVP_cleanup, OpenSSL.LIBCRYPTO), Void, ())
end

module Digest
import OpenSSL
import Base.ccall


function init()
ccall((:OpenSSL_add_all_digests, OpenSSL.LIBCRYPTO), Void, ())
end

function cleanup()
ccall((:EVP_cleanup, OpenSSL.LIBCRYPTO), Void, ())
end

function hexstring(hexes::Array{Uint8,1})
join([hex(h,2) for h in hexes], "")
end

function digest(name::String, data::String)

function digest(name::AbstractString, bs::Array{UInt8,1})
ctx = ccall((:EVP_MD_CTX_create, OpenSSL.LIBCRYPTO), Ptr{Void}, ())
try
# Get the message digest struct
md = ccall((:EVP_get_digestbyname, OpenSSL.LIBCRYPTO), Ptr{Void}, (Ptr{Uint8},), bytestring(name))
md = ccall((:EVP_get_digestbyname, OpenSSL.LIBCRYPTO), Ptr{Void}, (Ptr{UInt8},), name)
if(md == C_NULL)
error("Unknown message digest $name")
end
# Add the digest struct to the context
ccall((:EVP_DigestInit_ex, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{Void}, Ptr{Void}), ctx, md, C_NULL)
# Update the context with the input data
bs = bytestring(data)
ccall((:EVP_DigestUpdate, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{Uint8}, Uint), ctx, bs, length(bs))
# Update the context with the input data : bs
ccall((:EVP_DigestUpdate, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{UInt8}, UInt), ctx, bs, sizeof(bs))
# Figure out the size of the output string for the digest
size = ccall((:EVP_MD_size, OpenSSL.LIBCRYPTO), Uint, (Ptr{Void},), md)
uval = Array(Uint8, size)
size = ccall((:EVP_MD_size, OpenSSL.LIBCRYPTO), UInt, (Ptr{Void},), md)
uval = Array(UInt8, size)
# Calculate the digest and store it in the uval array
ccall((:EVP_DigestFinal_ex, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{Uint8}, Ptr{Uint}), ctx, uval, C_NULL)
# bytestring(uval)
# Convert the uval array to a string of hexes
return hexstring(uval)
ccall((:EVP_DigestFinal_ex, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{UInt8}, Ptr{UInt}), ctx, uval, C_NULL)
return uval
finally
ccall((:EVP_MD_CTX_destroy, OpenSSL.LIBCRYPTO), Void, (Ptr{Void},), ctx)
end
end#/digest

function digestinit(name::String)
function digestinit(name::AbstractString)
ctx = ccall((:EVP_MD_CTX_create, OpenSSL.LIBCRYPTO), Ptr{Void}, ())
try
# Get the message digest struct
md = ccall((:EVP_get_digestbyname, OpenSSL.LIBCRYPTO), Ptr{Void}, (Ptr{Uint8},), bytestring(name))
md = ccall((:EVP_get_digestbyname, OpenSSL.LIBCRYPTO), Ptr{Void}, (Ptr{UInt8},), name)
if(md == C_NULL)
error("Unknown message digest $name")
end
Expand All @@ -60,39 +67,147 @@ module OpenSSL
ccall((:EVP_MD_CTX_destroy, OpenSSL.LIBCRYPTO), Void, (Ptr{Void},), ctx)
nothing
end
end#/digest
end#/digestinit

function digestupdate(ctx,data::String)
function digestupdate(ctx, bs::Array{UInt8,1})
try
# Update the context with the input data
bs = bytestring(data)
ccall((:EVP_DigestUpdate, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{Uint8}, Uint), ctx, bs, length(bs))
# Update the context with the input data : bs
ccall((:EVP_DigestUpdate, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{UInt8}, UInt), ctx, bs, sizeof(bs))
ctx
catch
ccall((:EVP_MD_CTX_destroy, OpenSSL.LIBCRYPTO), Void, (Ptr{Void},), ctx)
nothing
end
end#/digest
end#/digestupdate

function digestfinalize(ctx)
try
# Get the message digest struct
md = ccall((:EVP_MD_CTX_md, OpenSSL.LIBCRYPTO), Ptr{Void}, (Ptr{Uint8},), ctx)
md = ccall((:EVP_MD_CTX_md, OpenSSL.LIBCRYPTO), Ptr{Void}, (Ptr{UInt8},), ctx)
if(md == C_NULL)
error("Unknown message digest $name")
end
size = ccall((:EVP_MD_size, OpenSSL.LIBCRYPTO), Uint, (Ptr{Void},), md)
uval = Array(Uint8, size)
size = ccall((:EVP_MD_size, OpenSSL.LIBCRYPTO), UInt, (Ptr{Void},), md)
uval = Array(UInt8, size)
# Calculate the digest and store it in the uval array
ccall((:EVP_DigestFinal_ex, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{Uint8}, Ptr{Uint}), ctx, uval, C_NULL)
# bytestring(uval)
# Convert the uval array to a string of hexes
return hexstring(uval)
ccall((:EVP_DigestFinal_ex, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{UInt8}, Ptr{UInt}), ctx, uval, C_NULL)
return uval
finally
ccall((:EVP_MD_CTX_destroy, OpenSSL.LIBCRYPTO), Void, (Ptr{Void},), ctx)
end
end#/digest
end#/digestfinalize

end#/Digest


module Cipher
import OpenSSL

function init()
ccall((:OpenSSL_add_all_ciphers, OpenSSL.LIBCRYPTO), Void, ())
end

function cleanup()
ccall((:EVP_cleanup, OpenSSL.LIBCRYPTO), Void, ())
end

function get_EVP_CIPHER(name::AbstractString)
# ec = ccall((:EVP_get_cipherbyname, OpenSSL.LIBCRYPTO), Ptr{Void}, (Ptr{UInt8},), name)
algorithm = "ccall((:EVP_$(name), OpenSSL.LIBCRYPTO), Ptr{Void}, ())"
ec = eval(parse(algorithm))
# ec = ccall((:EVP_aes_256_cbc, OpenSSL.LIBCRYPTO), Ptr{Void}, ())
if(ec == C_NULL)
error("Unknown cipher algorithm $name")
end
return ec
end

function encrypt(name::AbstractString, key::Array{UInt8,1}, iv::Array{UInt8,1}, plain::Array{UInt8,1}, selfpad::Bool=false)
ctx = ccall((:EVP_CIPHER_CTX_new, OpenSSL.LIBCRYPTO), Ptr{Void}, ())
ccall((:EVP_CIPHER_CTX_init, OpenSSL.LIBCRYPTO), Void, (Ptr{Void},), ctx)
try
ec = get_EVP_CIPHER(name)
ccall((:EVP_EncryptInit_ex, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{Void}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), ctx, ec, C_NULL, key, iv)

# :EVP_CIPHER_CTX_block_size must be after :EVP_EncryptInit_ex
blksize = ccall((:EVP_CIPHER_CTX_block_size, OpenSSL.LIBCRYPTO), UInt, (Ptr{Void},), ctx)
if(selfpad)
ccall((:EVP_CIPHER_CTX_set_padding, OpenSSL.LIBCRYPTO), UInt, (Ptr{Void}, UInt), ctx, 0) # disable
end
remain = sizeof(plain) % blksize
padlen = blksize - remain
enclen = sizeof(plain) + padlen
enc = Array(UInt8, enclen)
outlen = UInt(1) # start position = 1
tmpenc = Array(UInt8, blksize)
tmplen = Ref{Cint}(0)

for i in 1:div(sizeof(plain), blksize)
ccall((:EVP_EncryptUpdate, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{UInt8}, Ref{Cint}, Ptr{UInt8}, UInt), ctx, tmpenc, tmplen, plain[outlen:outlen+blksize-1], blksize)
if(tmplen[] > 0) enc[outlen:outlen+blksize-1] = tmpenc[1:blksize] end
outlen += tmplen[]
end

if(remain > 0)
ccall((:EVP_EncryptUpdate, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{UInt8}, Ref{Cint}, Ptr{UInt8}, UInt), ctx, tmpenc, tmplen, plain[outlen:outlen+remain-1], remain)
if(tmplen[] > 0) enc[outlen:outlen+remain-1] = tmpenc[1:remain] end
outlen += tmplen[]
end

if(selfpad && padlen != 0) # no use (padlen > 0), UInt is everytime > 0
# skip
# outlen += tmplen[]
end

if(!selfpad)
ccall((:EVP_EncryptFinal_ex, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{UInt8}, Ref{Cint}), ctx, tmpenc, tmplen)
if(tmplen[] > 0) enc[outlen:outlen+blksize-1] = tmpenc[1:blksize] end
outlen += tmplen[]
end

ccall((:EVP_CIPHER_CTX_cleanup, OpenSSL.LIBCRYPTO), Void, (Ptr{Void},), ctx)
return enc
finally
ccall((:EVP_CIPHER_CTX_free, OpenSSL.LIBCRYPTO), Void, (Ptr{Void},), ctx)
end
end#/encrypt

function decrypt(name::AbstractString, key::Array{UInt8,1}, iv::Array{UInt8,1}, cipher::Array{UInt8,1}, selfpad::Bool=false)
ctx = ccall((:EVP_CIPHER_CTX_new, OpenSSL.LIBCRYPTO), Ptr{Void}, ())
ccall((:EVP_CIPHER_CTX_init, OpenSSL.LIBCRYPTO), Void, (Ptr{Void},), ctx)
try
ec = get_EVP_CIPHER(name)
ccall((:EVP_DecryptInit_ex, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{Void}, Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}), ctx, ec, C_NULL, key, iv)

# :EVP_CIPHER_CTX_block_size must be after :EVP_DecryptInit_ex
blksize = ccall((:EVP_CIPHER_CTX_block_size, OpenSSL.LIBCRYPTO), UInt, (Ptr{Void},), ctx)
if(selfpad)
ccall((:EVP_CIPHER_CTX_set_padding, OpenSSL.LIBCRYPTO), UInt, (Ptr{Void}, UInt), ctx, 0) # disable
end
declen = sizeof(cipher) # trim padlen later
dec = Array(UInt8, declen)
outlen = UInt(1) # start position = 1
tmpdec = Array(UInt8, blksize)
tmplen = Ref{Cint}(0)

for i in 1:div(sizeof(cipher), blksize)
ccall((:EVP_DecryptUpdate, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{UInt8}, Ref{Cint}, Ptr{UInt8}, UInt), ctx, tmpdec, tmplen, cipher[outlen:outlen+blksize-1], blksize)
if(tmplen[] > 0) dec[outlen:outlen+blksize-1] = tmpdec[1:blksize] end
outlen += tmplen[]
end

if(!selfpad)
ccall((:EVP_DecryptFinal_ex, OpenSSL.LIBCRYPTO), Void, (Ptr{Void}, Ptr{UInt8}, Ref{Cint}), ctx, tmpdec, tmplen)
if(tmplen[] > 0) dec[outlen:outlen+blksize-1] = tmpdec[1:blksize] end
outlen += tmplen[]
end

ccall((:EVP_CIPHER_CTX_cleanup, OpenSSL.LIBCRYPTO), Void, (Ptr{Void},), ctx)
return selfpad ? dec[1:declen-dec[declen]] : dec[1:outlen-1]
finally
ccall((:EVP_CIPHER_CTX_free, OpenSSL.LIBCRYPTO), Void, (Ptr{Void},), ctx)
end
end#/decrypt

end#/Cipher

end#/OpenSSL
7 changes: 5 additions & 2 deletions test/data.jl
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
sha512_of_test = "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"
md5_of_test = "098f6bcd4621d373cade4e832627b4f6"
sha512_of_test = hex2bytes("ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff")
md5_of_test = hex2bytes("098f6bcd4621d373cade4e832627b4f6")
md5_of_bytes = hex2bytes("e299ff9d8e4831f07e5323913c53e5f0")
aes256cbc_of_shortdata = hex2bytes("da8aab1b904205a7e49c1ecc7118a8f4")
aes256cbc_of_longdata = hex2bytes("da8aab1b904205a7e49c1ecc7118a8f4804bef7be79216196739de7845da182d")
4 changes: 4 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using OpenSSL
using Base.Test

include("test.jl")
52 changes: 46 additions & 6 deletions test/test.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,52 @@
require("OpenSSL")
import OpenSSL
using Base.Test

include("data.jl")

assert(isdefined(:OpenSSL))
OpenSSL.Digest.init()
@test isdefined(:OpenSSL) == true
OpenSSL.init()

assert(OpenSSL.Digest.digest("SHA512", "test") == sha512_of_test)
assert(OpenSSL.Digest.digest("MD5", "test") == md5_of_test)
s = OpenSSL.Digest.digest("SHA512", "test".data)
println(s)
@test s == sha512_of_test

OpenSSL.Digest.cleanup()
m = OpenSSL.Digest.digest("MD5", "test".data)
println(m)
@test m == md5_of_test

h = OpenSSL.Digest.digest("MD5",
hex2bytes("5365637265742050617373706872617365a3e550e89e70996c"))
println(h)
@test h == md5_of_bytes

key32 = hex2bytes("e299ff9d8e4831f07e5323913c53e5f0"*
"fec3a040a211d6562fa47607244d0051")
iv16 = hex2bytes("7c7ed9434ddb9c2d1e1fcc38b4bf4667")

### selfpad=true
#plainshort = "Message\t\t\t\t\t\t\t\t\t".data
#plainlong = "Message\t\t\t\t\t\t\t\t\t"*
# "\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10".data

### selfpad=false
plainshort = "Message".data
plainlong = "Message\t\t\t\t\t\t\t\t\t".data

es = OpenSSL.Cipher.encrypt("aes_256_cbc", key32, iv16, plainshort)
println(es)
@test es == aes256cbc_of_shortdata

ds = OpenSSL.Cipher.decrypt("aes_256_cbc", key32, iv16, es)
println(ds)
@test ds == plainshort

el = OpenSSL.Cipher.encrypt("aes_256_cbc", key32, iv16, plainlong)
println(el)
@test el == aes256cbc_of_longdata

dl = OpenSSL.Cipher.decrypt("aes_256_cbc", key32, iv16, el)
println(dl)
@test dl == plainlong

OpenSSL.cleanup()
println("All tests passed")