Skip to content

Commit

Permalink
FEAT: added ssh-key (Secure Shell Key) codec (so far only RSA keys)
Browse files Browse the repository at this point in the history
  • Loading branch information
Oldes committed Jun 9, 2020
1 parent 3d1436a commit 4c07b7a
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/mezz/boot-files.r
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,20 @@ REBOL [
%mezz-date.r ; Internet date support
;%mezz-tag.r ; build-tag
%mezz-tail.r
%codec-json.r
%codec-unixtime.r
;- cryptographic
%codec-utc-time.r
%codec-pkix.r
%codec-der.r
%codec-crt.r
%codec-ssh-key.r
;- compression
%codec-gzip.r
%codec-xml.r
%codec-zip.r
%codec-tar.r
;- other
%codec-json.r
%codec-xml.r
%codec-html-entities.r
; optional files added in make-boot.r per os and product
;%codec-wav.r
Expand Down
144 changes: 144 additions & 0 deletions src/mezz/codec-ssh-key.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
REBOL [
Title: "REBOL 3 codec: Secure Shell Key"
Author: "Oldes"
Rights: "Copyright (C) 2018 Oldes. All rights reserved."
License: "BSD-3"
Test: %tests/units/crypt-test.r3
Note: {
* it extract (and inits) only RSA keys so far
* encrypted keys only with `AES-128-CBC` encryption
}
]

wrap [
init-from-ssh2-key: function [data][
try [
binary/read data [
v: UI32BYTES
e: UI32BYTES
n: UI32BYTES
]
v: to string! v
if v = "ssh-rsa" [
return rsa-init n e
]
]
print ["Not RSA key! (" v ")"]
none
]

register-codec [
name: 'ssh-key
title: "Secure Shell Key"
; not using suffixes as there is no standard!

decode: function [
"Decodes and initilize SSH key"
key [binary! string! file!]
/password p [string! binary!] "Optional password"
][
case [
file? key [ key: read key ]
string? key [ key: to binary! key ]
]
; try to load key as a PKIX structure
try [ pkix: codecs/pkix/decode key ]
if none? pkix [
; if failed to load as PKIX, try to treat it as a *.PUB file
return either parse key [
"ssh-rsa " copy data to [#" " | end] to end
][ init-from-ssh2-key debase data 64
][ init-from-ssh2-key key ]
]
if "4,ENCRYPTED" = select pkix/header "Proc-Type" [
print "ENCRYPTED key!"
try/except [
dek-info: select pkix/header "DEK-Info"
;probe dek-info
parse dek-info [
"AES-128-CBC" #"," copy iv to end
]
iv: debase iv 16
unless password [p: ask/hide "Pasword: "]
p: checksum/method
join to binary! p copy/part iv 8
'md5
d: aes/key/decrypt p iv
pkix/binary: aes/stream d pkix/binary
][ return none ]
]

switch pkix/label [
"SSH2 PUBLIC KEY" [
return init-from-ssh2-key pkix/binary
]
]
; decode DER structure from decoded PKIX binary
try/except [
data: codecs/der/decode pkix/binary
][
print "Failed to decode DER day for RSA key!"
probe system/state/last-error
return none
]

switch pkix/label [
"PUBLIC KEY" [
; resolve RSA public data from the DER structure (PKCS#1)
all [
parse data [
'SEQUENCE into [
'SEQUENCE set v block! ; AlgorithmIdentifier
'BIT_STRING set data binary! ; PublicKey
(
data: codecs/der/decode data
)
]
]
v/OBJECT_IDENTIFIER = #{2A864886F70D010101} ;= rsaEncryption
parse data [
'SEQUENCE into [
'INTEGER set n binary! ;modulus
'INTEGER set e binary! ;publicExponent
]
]
]
; resolve RSA handle from parsed data
return rsa-init n e
]
"RSA PUBLIC KEY" [
; resolve RSA public data from the DER structure (PKCS#1)
parse data [
'SEQUENCE into [
'INTEGER set n binary! ;modulus
'INTEGER set e binary! ;publicExponent
]
]
; resolve RSA handle from parsed data
return rsa-init n e
]
"RSA PRIVATE KEY" [
; resolve RSA private data from the DER structure (PKCS#1)
parse data [
'SEQUENCE into [
'INTEGER set v binary! ;version
'INTEGER set n binary! ;modulus
'INTEGER set e binary! ;publicExponent
'INTEGER set d binary! ;privateExponent
'INTEGER set p binary! ;prime1
'INTEGER set q binary! ;prime2
'INTEGER set dp binary! ;exponent1 d mod (p-1)
'INTEGER set dq binary! ;exponent2 d mod (q-1)
'INTEGER set inv binary! ;coefficient (inverse of q) mod p
to end
]
to end
]
; resolve RSA handle from parsed data
return rsa-init/private n e d p q dp dq inv
]
]
none ; no success!
]
]
]
8 changes: 8 additions & 0 deletions src/tests/units/crypt-test.r3
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV

--assert block? Load-PKIX pkix
--assert binary? Load-PKIX/binary pkix
--assert error? try [decode 'ssh-key pkix] ;- because it contains unsupported ssh-dss


--test-- "SSH-public-key-3"
pkix:
Expand Down Expand Up @@ -217,4 +219,10 @@ sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV

===end-group===


===start-group=== "SSH-key codec"
--test-- "Init RSA key from file"
--assert handle? try [key: decode 'ssh-key read %units/files/rebol-public.ppk]
rsa key none ; release it, as it is not GCed yet.

~~~end-file~~~
9 changes: 9 additions & 0 deletions src/tests/units/files/rebol-public.ppk
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "rsa-key-rebol-test"
AAAAB3NzaC1yc2EAAAABJQAAAQEA8mjwC6ZCwpQCnDXqU7g2tyvMFoWpJV+myfBz
9zbhw7rHxUmFubMtEwCKQhYccQxbPCcWu/KIg5TOhmcf9RK1xIuUrOUiUdM8uOwR
S+e5kitTUgux/wjyMNlpK5laIS1hFHiFhCxecN7Won3bsPDMm5Wi3dBMv1+1jK1r
lDtJYxDDcJE2T59m1UI4AN/Pm7dndr11yCmUdKy6VACf5V7u4OX5uC3fsTEuCV1P
2WwLBqtZMYG3jjzuRTana+s8n2TXk5D9lXoPMc7Tj4/aSw50UUAYhmVpie/8vtVw
A7MhOCA4us6q3+Mx07vq8EmzbLOGtP9taXQkDF6JR6wY4IEXBw==
---- END SSH2 PUBLIC KEY ----

0 comments on commit 4c07b7a

Please sign in to comment.