Skip to content

Instantly share code, notes, and snippets.

@mikofski
Last active March 13, 2020 20:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikofski/7028865 to your computer and use it in GitHub Desktop.
Save mikofski/7028865 to your computer and use it in GitHub Desktop.
MATLAB version of javaDigest EncryptionUtil from http://javadigest.wordpress.com/2012/08/26/rsa-encryption-example/
classdef EncryptionUtil
%% A class of static encryption methods
% attributions:
%
% * http://javadigest.wordpress.com/2012/08/26/rsa-encryption-example/
% * http://stackoverflow.com/a/19435226/1020470
%% Constants
properties (Constant)
ALGORITHM = 'RSA' % Encryption algorithm.
% Names of the key files.
HOME = getenv('HOME');MATHOME = fullfile('Documents','MATLAB');
NAME = fullfile(EncryptionUtil.HOME,EncryptionUtil.MATHOME,mfilename);
PRIVATE_KEY_FILE = fullfile(EncryptionUtil.NAME,'keys','private.key')
PRIVATE_ENCKEY = fullfile(EncryptionUtil.NAME,'keys','privateEncoded.key')
PRIVATE_JSCH_KEY = fullfile(EncryptionUtil.NAME,'keys','privateJsch.key')
% String to hold name of the public key file.
PUBLIC_KEY_FILE = fullfile(EncryptionUtil.NAME,'keys','public.key')
PUBLIC_ENCKEY = fullfile(EncryptionUtil.NAME,'keys','publicEncoded.key')
PUBLIC_JSCH_KEY = fullfile(EncryptionUtil.NAME,'keys','publicJsch.key')
PUBLIC_JSCH_SECSH = fullfile(EncryptionUtil.NAME, ...
'keys','publicJschSECSH.key')
% BASE64 Encoder
BASE64ENCODER = org.apache.commons.codec.binary.Base64;
end
%% Static Methods
methods (Static)
%% Generate keys using Java, save as Java Encoded, and write SSH keys
% requires Jsch (http://www.jcraft.com/jsch/)
function generateKey(keysize)
% GENERATEKEY(KEYSIZE)
% Generate key which contains a pair of private and public key
% using KEYSIZE bytes. Store the set of keys in Prvate.key and
% Public.key files. Default size is 1024-bits.
if nargin<1,keysize = 1024;end % set default
try
%% java.security.KeyPair
keyGen = java.security.KeyPairGenerator.getInstance( ...
EncryptionUtil.ALGORITHM);
keyGen.initialize(keysize);
key = keyGen.generateKeyPair;
privateKeyFile = java.io.File(EncryptionUtil.PRIVATE_KEY_FILE);
publicKeyFile = java.io.File(EncryptionUtil.PUBLIC_KEY_FILE);
% Create files to store public and private key
if ~isempty(privateKeyFile.getParentFile)
privateKeyFile.getParentFile.mkdirs;
end
privateKeyFile.createNewFile;
if ~isempty(publicKeyFile.getParentFile)
publicKeyFile.getParentFile.mkdirs;
end
publicKeyFile.createNewFile;
% Saving the Public key in a file
publicKeyOS = java.io.ObjectOutputStream( ...
java.io.FileOutputStream(publicKeyFile));
publicKeyOS.writeObject(key.getPublic);
publicKeyOS.close;
% Saving the Private key in a file
privateKeyOS = java.io.ObjectOutputStream( ...
java.io.FileOutputStream(privateKeyFile));
privateKeyOS.writeObject(key.getPrivate);
privateKeyOS.close;
%% save Java Encoded Keys
% save encoded public key (X.509)
fw = java.io.FileWriter(EncryptionUtil.PUBLIC_ENCKEY);
fw.write(java.lang.String( ...
EncryptionUtil.BASE64ENCODER.encode( ...
key.getPublic.getEncoded)))
fw.close
% save encoded public key (PKCS#8)
fw = java.io.FileWriter(EncryptionUtil.PRIVATE_ENCKEY);
fw.write(java.lang.String( ...
EncryptionUtil.BASE64ENCODER.encode( ...
key.getPrivate.getEncoded)))
fw.close
catch ME
publicKeyOS.close;
privateKeyOS.close;
fw.close
rethrow(ME)
end
%% com.jcraft.jsch.KeyPair
JSCH = com.jcraft.jsch.JSch; % create new JSch object
RSA = com.jcraft.jsch.KeyPair.RSA; % RSA
try
% Creates a new key pair with default key size of 1024 bits.
keyGenJsch = com.jcraft.jsch.KeyPair.genKeyPair(JSCH, RSA, keysize);
keyGenJsch.writePrivateKey(EncryptionUtil.PRIVATE_JSCH_KEY)
keyGenJsch.writePublicKey(EncryptionUtil.PUBLIC_JSCH_KEY, ...
'testReadWriteSSHKeyPair')
keyGenJsch.writeSECSHPublicKey( ...
EncryptionUtil.PUBLIC_JSCH_SECSH,'testReadWriteSSHKeyPair')
catch ME
rethrow(ME)
end
end
%% checks to make sure keys exist before testing
function tf = areKeysPresent
% The method checks if the pair of public and private key has been
% generated.
privateKey = java.io.File(EncryptionUtil.PRIVATE_KEY_FILE);
publicKey = java.io.File(EncryptionUtil.PUBLIC_KEY_FILE);
if (privateKey.exists && publicKey.exists)
tf = true;
return
end
tf = false;
end
function tf = areEncKeysPresent
% The method checks if the pair of public and private key has been
% generated.
privateKey = java.io.File(EncryptionUtil.PRIVATE_ENCKEY);
publicKey = java.io.File(EncryptionUtil.PUBLIC_ENCKEY);
if (privateKey.exists && publicKey.exists)
tf = true;
return
end
tf = false;
end
function tf = areJschKeysPresent
% The method checks if the pair of public and private key has been
% generated.
privateKey = java.io.File(EncryptionUtil.PRIVATE_JSCH_KEY);
publicKey = java.io.File(EncryptionUtil.PUBLIC_JSCH_KEY);
publicSECSHKey = java.io.File(EncryptionUtil.PUBLIC_JSCH_SECSH);
if (privateKey.exists && publicKey.exists && publicSECSHKey.exists)
tf = true;
return
end
tf = false;
end
%% Encrypt text using Java public key
function cipherText = encrypt(text,key)
% Encrypt the plain text using public key.
try
% get an RSA cipher object and print the provider
cipher = javax.crypto.Cipher.getInstance( ...
EncryptionUtil.ALGORITHM);
% encrypt the plain text using the public key
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key);
cipherText = cipher.doFinal(uint8(text));
catch ME
rethrow(ME)
end
end
%% Decrypt text using Java private key
function decryptedText = decrypt(text, key)
% Decrypt text using private key.
try
% get an RSA cipher object and print the provider
cipher = javax.crypto.Cipher.getInstance( ...
EncryptionUtil.ALGORITHM);
% decrypt the text using the private key
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, key);
decryptedText = char(cipher.doFinal(text));
catch ME
rethrow(ME)
end
end
%% test keys by encrypting/decrypting text
function test(originalText)
% TEST(ORIGINALTEXT) encrypt/decrypt ORIGINALTEXT
% Test the EncryptionUtil
try
% Check if the pair of keys are present else generate those.
if ~EncryptionUtil.areKeysPresent
% Method generates a pair of keys using the RSA algorithm
% and stores it in their respective files
EncryptionUtil.generateKey;
end
% encryption text.
if nargin<1,originalText = 'Text to be encrypted';end
% read public key Object from file.
inputStream = java.io.ObjectInputStream( ...
java.io.FileInputStream(EncryptionUtil.PUBLIC_KEY_FILE));
publicKey = inputStream.readObject;
inputStream.close
% Encrypt the string using the public key.
cipherText = EncryptionUtil.encrypt(originalText, publicKey);
% read private key object from file.
inputStream = java.io.ObjectInputStream( ...
java.io.FileInputStream(EncryptionUtil.PRIVATE_KEY_FILE));
privateKey = inputStream.readObject;
inputStream.close
% Decrypt the cipher text using the private key.
plainText = EncryptionUtil.decrypt(cipherText, privateKey);
% Printing the Original, Encrypted and Decrypted Text.
java.lang.System.out.println(['Original Text: ',originalText]);
java.lang.System.out.println(['Encrypted Text: ', ...
char(cipherText)']);
java.lang.System.out.println(['Decrypted Text: ',plainText']);
catch ME
inputStream.close
rethrow(ME)
end
end
function testEncoded(originalText)
% Test the EncryptionUtil with encoded keys
% private keys are encoded with PKCS8EncodedKeySpec
% public keys are encoded with X509EncodedKeySpec
try
% Check if the pair of keys are present else generate those.
if ~EncryptionUtil.areEncKeysPresent
% Method generates a pair of keys using the RSA algorithm
% and stores it in their respective files
EncryptionUtil.generateKey;
end
% encryption text
if nargin<1,originalText = 'Text to be encrypted';end
% read encoded public key from file
keybuf = java.io.BufferedReader(java.io.FileReader( ...
EncryptionUtil.PUBLIC_ENCKEY));
keyln = keybuf.readLine;
encKey = EncryptionUtil.BASE64ENCODER.decode(keyln.getBytes);
% only one line!
keybuf.close
% generate public key from encoded bytes using Spec & KeyFactory
pubKeySpec = java.security.spec.X509EncodedKeySpec(encKey);
keyFactory = java.security.KeyFactory.getInstance('RSA');
publicKey = keyFactory.generatePublic(pubKeySpec);
% Encrypt the string using the public key
cipherText = EncryptionUtil.encrypt(originalText, publicKey);
% read encoded private key from file
keybuf = java.io.BufferedReader(java.io.FileReader( ...
EncryptionUtil.PRIVATE_ENCKEY));
keyln = keybuf.readLine;
encKey = EncryptionUtil.BASE64ENCODER.decode(keyln.getBytes);
% only one line!
keybuf.close
% generate private key from encoded bytes using Spec & KeyFactory
privKeySpec = java.security.spec.PKCS8EncodedKeySpec(encKey);
keyFactory = java.security.KeyFactory.getInstance('RSA');
privateKey = keyFactory.generatePrivate(privKeySpec);
% Decrypt the cipher text using the private key.
plainText = EncryptionUtil.decrypt(cipherText, privateKey);
% Printing the Original, Encrypted and Decrypted Text
java.lang.System.out.println(['Original Text: ',originalText]);
java.lang.System.out.println(['Encrypted Text: ', ...
char(cipherText)']);
java.lang.System.out.println(['Decrypted Text: ',plainText']);
catch ME
keybuf.close
rethrow(ME)
end
end
function testJschSECSH(originalText)
% Test the EncryptionUtil with Jsch keys
try
% Check if the pair of keys are present else generate those.
if ~EncryptionUtil.areJschKeysPresent
% Method generates a pair of keys using the RSA algorithm
% and stores it in their respective files
EncryptionUtil.generateKey;
end
% encryption text
if nargin<1,originalText = 'Text to be encrypted';end
% key factory
keyFactory = java.security.KeyFactory.getInstance('RSA');
% read OpenSSH public key from file
[keyln,totalLines] = EncryptionUtil.readJschKeyFile( ...
EncryptionUtil.PUBLIC_JSCH_SECSH);
% join lines
keystr = EncryptionUtil.joinLines(keyln,totalLines,2,1);
% convert SSH RSA public key
publicKey = EncryptionUtil.convertSSHPublicKey(keystr,keyFactory);
% read OpenSSH private key from file
[keyln,totalLines] = EncryptionUtil.readJschKeyFile( ...
EncryptionUtil.PRIVATE_JSCH_KEY);
% join lines
keystr = EncryptionUtil.joinLines(keyln,totalLines,1,1);
% convert SSH RSA private key
privateKey = EncryptionUtil.convertSSHPrivateKey(keystr,keyFactory);
% compare keys
assert(publicKey.getModulus.equals(privateKey.getModulus), ...
'EncryptionUtil:testJschSECSH','Modulus does not match.')
assert(publicKey.getPublicExponent.equals(privateKey.getPublicExponent), ...
'EncryptionUtil:testJschSECSH','Exponent does not match.')
% Encrypt the string using the public key
cipherText = EncryptionUtil.encrypt(originalText, publicKey);
% Decrypt the cipher text using the private key.
plainText = EncryptionUtil.decrypt(cipherText, privateKey);
% Printing the Original, Encrypted and Decrypted Text
java.lang.System.out.println(['Original Text: ', originalText]);
java.lang.System.out.println(['Encrypted Text: ', char(cipherText)']);
java.lang.System.out.println(['Decrypted Text: ', plainText']);
catch ME
rethrow(ME)
end
end
%% Read key file into Java String Array
function [keyln,totalLines] = readJschKeyFile(file, nlines)
if nargin<2,nlines = 10;end
% open file
try
keybuf = java.io.BufferedReader(java.io.FileReader(file));
lnIdx = 1; % line index
keyln = javaArray('java.lang.String',nlines); % string array
% read lines into string array
keyln(lnIdx) = keybuf.readLine;
fprintf('key line: %s\n',char(keyln(lnIdx))) % read line
while ~isempty(keyln(lnIdx))
lnIdx = lnIdx+1; % line index
keyln(lnIdx) = keybuf.readLine;
fprintf('key line: %s\n',char(keyln(lnIdx)))
end
keybuf.close
% total lines minus last line
totalLines = lnIdx-1;fprintf('total lines: %d\n',totalLines)
catch ME
keybuf.close
rethrow(ME)
end
end
%% Concatenate String Array
function keystr = joinLines(keyln,totalLines,headers,footers)
% join lines
keystr = java.lang.StringBuilder;
for lnIdx = headers+1:totalLines-footers
keystr.append(keyln(lnIdx));
end
% key string
keystr = keystr.toString;fprintf('key: %s\n',char(keystr))
end
%% Read key data (modulus, exponent, ...)
function [buf,idx] = lenval(encKey,idx)
% get the number of bytes to read and read them into BUF
% return position of pointer, IDX, after reading BUF
len = double(swapbytes(typecast(encKey(idx:idx+3),'uint32')));
idxs = idx+4:idx+3+len;
buf = encKey(idxs);
idx = idx+4+len;
end
%% Convert SSH public key to Java
function publicKey = convertSSHPublicKey(keystr, keyFactory)
% ASN.1 PKCS#1 (v2.1) format (see rfc3447)
% http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One
% http://en.wikipedia.org/wiki/PKCS1
% http://tools.ietf.org/html/rfc3447
% base64 decode
encKey = EncryptionUtil.BASE64ENCODER.decode(keystr.getBytes);
fprintf('number of Bytes: %d\n',numel(encKey)); % number of bytes
% key type [5:11]
[buf,idx] = EncryptionUtil.lenval(encKey,1);
fprintf('position: %d\n',idx)
keyType = char(buf)'; % public key type
assert(strcmp(keyType,'ssh-rsa'), ...
'EncryptionUtil:testJschSECSH', ...
'Key type "%s" is not "ssh-rsa".',keyType)
% public exponent [16:18]
[buf,idx] = EncryptionUtil.lenval(encKey,idx);
fprintf('position: %d\n',idx)
exp = java.math.BigInteger(1, buf); % exponent
% modulus [23:151]
[buf,idx] = EncryptionUtil.lenval(encKey,idx);
fprintf('position: %d\n',idx)
mod = java.math.BigInteger(1, buf); % modulus
% public key
publicKey = keyFactory.generatePublic( ...
java.security.spec.RSAPublicKeySpec(mod, exp));
end
%% convert SSH private key to Java
function privateKey = convertSSHPrivateKey(keystr, keyFactory)
% ASN.1 PKCS#1 (v2.1) format (see rfc3447)
% http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One
% http://en.wikipedia.org/wiki/PKCS1
% http://tools.ietf.org/html/rfc3447
% base64 decode
encKey = EncryptionUtil.BASE64ENCODER.decode(keystr.getBytes);
fprintf('number of Bytes: %d\n',numel(encKey)); % number of bytes
% asn.1 header & key length [1]
prvkeyLen = swapbytes(typecast(encKey(3:4),'uint16'));
asn1seq = cellstr(dec2hex(typecast(encKey(1:2),'uint8')));
asn1seq = ['x',asn1seq{:}]; % ASN.1 Sequence (x3082)
assert(strcmp(asn1seq,'x3082'), ...
'EncryptionUtil:testJschSECSH', ...
'Key is not an ASN.1 sequence. Header contains %s.',asn1seq)
fprintf('asn.1 header: %s == asn.1 sequence\nlength: %d bytes\n', ...
asn1seq,prvkeyLen)
% TODO: refactor to remove reduntancy, DER process repeats!
% key version [5]
idx = 5;
[verLen,idx] = EncryptionUtil.lenDer(encKey,idx);
keyVer = typecast(encKey(idx+1:idx+verLen),'uint8');
fprintf('version: %d\n',keyVer)
% modulus [8]
idx = idx+verLen+1;fprintf('position: %d\n',idx)
[modLen,idx] = EncryptionUtil.lenDer(encKey,idx);
mod = java.math.BigInteger(1, encKey(idx+1:idx+modLen));
% public exponent [140]
idx = idx+modLen+1;fprintf('position: %d\n',idx)
[pubExpLen,idx] = EncryptionUtil.lenDer(encKey,idx);
pubExp = java.math.BigInteger(1, encKey(idx+1:idx+pubExpLen));
% private exponent [145]
idx = idx+pubExpLen+1;fprintf('position: %d\n',idx)
[prvExpLen,idx] = EncryptionUtil.lenDer(encKey,idx);
prvExp = java.math.BigInteger(1, encKey(idx+1:idx+prvExpLen));
% prime P [276]
idx = idx+prvExpLen+1;fprintf('position: %d\n',idx)
[primePLen,idx] = EncryptionUtil.lenDer(encKey,idx);
primeP = java.math.BigInteger(1, encKey(idx+1:idx+primePLen));
% prime Q [343]
idx = idx+primePLen+1;fprintf('position: %d\n',idx)
[primeQLen,idx] = EncryptionUtil.lenDer(encKey,idx);
primeQ = java.math.BigInteger(1, encKey(idx+1:idx+primeQLen));
% prime exponent P [410]
idx = idx+primeQLen+1;fprintf('position: %d\n',idx)
[primeExpPLen,idx] = EncryptionUtil.lenDer(encKey,idx);
primeExpP = java.math.BigInteger(1, encKey(idx+1:idx+primeExpPLen));
% prime exponent Q [477]
idx = idx+primeExpPLen+1;fprintf('position: %d\n',idx)
[primeExpQLen,idx] = EncryptionUtil.lenDer(encKey,idx);
primeExpQ = java.math.BigInteger(1, encKey(idx+1:idx+primeExpQLen));
% prime coefficient [543]
idx = idx+primeExpQLen+1;fprintf('position: %d\n',idx)
[coeffLen,idx] = EncryptionUtil.lenDer(encKey,idx);
coeff = java.math.BigInteger(1, encKey(idx+1:idx+coeffLen));
% private key
privateKey = keyFactory.generatePrivate( ...
java.security.spec.RSAPrivateCrtKeySpec(mod, pubExp, prvExp, ...
primeP, primeQ, primeExpP, primeExpQ, coeff));
end
%% write Java public key in OpenSSH format
function publicSSHKey = writeSSHPublicKey(publicKey,filename,comment)
% write SSH public key
if nargin<2,filename = 'publicSSH.key';end
if nargin<3
if ispc
comment = sprintf('%s@%s', ...
getenv('USERNAME'),getenv('COMPUTERNAME'));
else
comment = sprintf('%s@%s', ...
getenv('USERNAME'),getenv('HOSTNAME'));
end
end
mod = publicKey.getModulus;
exp = publicKey.getPublicExponent;
keyTypeLen = typecast(swapbytes(uint32(7)),'int8')';
keyType = int8('ssh-rsa')';
modBytes = mod.toByteArray;
modLen = typecast(swapbytes(uint32(numel(modBytes))),'int8')';
expBytes = exp.toByteArray;
expLen = typecast(swapbytes(uint32(numel(expBytes))),'int8')';
encKey = [keyTypeLen;keyType;expLen;expBytes;modLen;modBytes];
encKey = EncryptionUtil.BASE64ENCODER.encode(encKey)';
encKey = char(typecast(encKey,'uint8'))';
BEGINSSH = '---- BEGIN SSH2 PUBLIC KEY ----';
ENDSSH = '---- END SSH2 PUBLIC KEY ----';
publicSSHKey = sprintf('%s\nComment: "%s"\n',BEGINSSH,comment);
lineLen = 70;nlines = floor(numel(encKey)/lineLen);
for l = 1:nlines
publicSSHKey = [publicSSHKey, ...
sprintf('%64s\n',encKey(lineLen*(l-1)+1:lineLen*l))]; %#ok<AGROW>
end
publicSSHKey = [publicSSHKey, ...
sprintf('%s\n%s\n',encKey(l*lineLen+1:end),ENDSSH)];
try
fid = fopen(filename,'wt');
fwrite(fid,publicSSHKey);
fclose(fid);
catch ME
fclose(fid);
throw(ME)
end
end
%% write Java private key in OpenSSH format
function privateSSHKey = writeSSHPrivateKey(privateKey,filename)
% write SSH private key
if nargin<2,filename = 'privateSSH.key';end
mod = privateKey.getModulus;
pubExp = privateKey.getPublicExponent;
prvExp = privateKey.getPrivateExponent;
primeP = privateKey.getPrimeP;
primeQ = privateKey.getPrimeQ;
expP = privateKey.getPrimeExponentP;
expQ = privateKey.getPrimeExponentQ;
coeff = privateKey.getCrtCoefficient;
% ASN.1 header sequence
integer = int8(2); % asn.1 integer type
asn1seq = typecast(uint8(cellfun(@hex2dec,{'30';'82'})),'int8');
keyVer = int8(0); % version 0
verLen = numel(keyVer); % version length in bytes
% convert big integers to byte arrays
modBytes = mod.toByteArray;
pubExpBytes = pubExp.toByteArray;
prvExpBytes = prvExp.toByteArray;
primePBytes = primeP.toByteArray;
primeQBytes = primeQ.toByteArray;
expPBytes = expP.toByteArray;
expQBytes = expQ.toByteArray;
coeffBytes = coeff.toByteArray;
% byte array lengths
modLen = numel(modBytes);
pubExpLen = numel(pubExpBytes);
prvExpLen = numel(prvExpBytes);
primePLen = numel(primePBytes);
primeQLen = numel(primeQBytes);
expPLen = numel(expPBytes);
expQLen = numel(expQBytes);
coeffLen = numel(coeffBytes);
% key length in bytes
keyLen = sum([2,verLen,3,modLen,2,pubExpLen,3,prvExpLen, ...
2,primePLen,2,primeQLen,2,expPLen,2,expQLen,2,coeffLen]);
keyLen = typecast(swapbytes(uint16(keyLen)),'int8')'; % length of key
% byte array lengths
verLen = EncryptionUtil.derlen(verLen);
modLen = EncryptionUtil.derlen(modLen);
pubExpLen = EncryptionUtil.derlen(pubExpLen);
prvExpLen = EncryptionUtil.derlen(prvExpLen);
primePLen = EncryptionUtil.derlen(primePLen);
primeQLen = EncryptionUtil.derlen(primeQLen);
expPLen = EncryptionUtil.derlen(expPLen);
expQLen = EncryptionUtil.derlen(expQLen);
coeffLen = EncryptionUtil.derlen(coeffLen);
% make DER
encKey = [asn1seq;keyLen; ... % ASN.1 Sequence & key length
integer;verLen;keyVer; ... % key version
integer;modLen;modBytes; ... % modulus
integer;pubExpLen;pubExpBytes; ... % public exponent
integer;prvExpLen;prvExpBytes; ... % private exponent
integer;primePLen;primePBytes; ... % prime P
integer;primeQLen;primeQBytes; ... % prime Q
integer;expPLen;expPBytes; ... % prime P exponent
integer;expQLen;expQBytes; ... % prime Q exponent
integer;coeffLen;coeffBytes]; % CRT coefficient
encKey = EncryptionUtil.BASE64ENCODER.encode(encKey)';
encKey = char(typecast(encKey,'uint8'))';
BEGINRSA = '-----BEGIN RSA PRIVATE KEY-----';
ENDRSA = '-----END RSA PRIVATE KEY-----';
privateSSHKey = sprintf('%s\n',BEGINRSA);
lineLen = 64;nlines = floor(numel(encKey)/lineLen);
for l = 1:nlines
privateSSHKey = [privateSSHKey, ...
sprintf('%64s\n',encKey(lineLen*(l-1)+1:lineLen*l))]; %#ok<AGROW>
end
privateSSHKey = [privateSSHKey, ...
sprintf('%s\n%s\n',encKey(l*lineLen+1:end),ENDRSA)];
try
fid = fopen(filename,'wt');
fwrite(fid,privateSSHKey);
fclose(fid);
catch ME
fclose(fid);
throw(ME)
end
end
%% DER value length
% DER parses anything over 7 bits into more than 2 bytes
function len = derlen(len)
% convert length as double to DER bytes
if len<128
% return length in 1-byte if less than 128
len = typecast(uint8(len),'int8');
return
else
% number of bits required
nlen = nextpow2(len+1); % number of bits
end
if nlen == 8
% 8-bit integer (1-byte)
len = typecast([uint8(128+1);uint8(len)],'int8'); % append # of bytes
elseif nlen == 9
% 16-bit integer (2-bytes)
len = [typecast(uint8(128+2),'int8'), ...
typecast(swapbytes(uint16(len)),'int8')]'; % append # of bytes
else
error('EncryptionUtil:derlen','Length is greater than 16-bits.')
end
end
function [len,idx] = lenDer(encKey,idx)
% convert DER bytes to length as double
assert(encKey(idx)==2,'EncryptionUtil:lenDer', ...
'The private key was not parsed correctly.')
idx = idx+1; % increment pointer
len = double(typecast(encKey(idx),'uint8'));
if len<128
% return if less than 128, length stored in only 1-byte
return
else
% number of bytes required, [1 or 2] only
nlen = mod(len,128); % number of bytes, [1 or 2] only
end
if nlen == 1
% 8-bit integer (1-byte)
idx = idx+nlen; % increment pointer
len = double(typecast(encKey(idx),'uint8'));
elseif nlen == 2
% 16-bit integer (2-byte)
idx = idx+nlen; % increment pointer
len = double(swapbytes(typecast(encKey(idx-1:idx),'uint16')));
else
error('EncryptionUtil:lenDer','Length is greater than 16-bits.')
end
end
%% write Java key pair in OpenSSH format
function [publicSSHKey,privateSSHKey] = writeSSHKeys(publicKey,privateKey,varargin)
pubvarargin = varargin;
if numel(pubvarargin)>0
pubvarargin{1} = [pubvarargin{1},'.pub'];
end
if numel(varargin)>0
varargin = varargin(1);
end
publicSSHKey = EncryptionUtil.writeSSHPublicKey(publicKey,pubvarargin{:});
privateSSHKey = EncryptionUtil.writeSSHPrivateKey(privateKey,varargin{:});
end
end
end
%% initialize workspace
close('all'),clear('all'),clc
rmdir('keys','s') % delete old keys
%% test encryption
PANGRAM = 'The quick brown fox jumped over the lazy dog.';
EncryptionUtil.testJschSECSH(PANGRAM) % run test
%% make SSH keys in workspace
keyFactory = java.security.KeyFactory.getInstance('RSA'); % make a key factory
% read public OpenSSH key
[keyln, totlines] = EncryptionUtil.readJschKeyFile('keys/publicJschSECSH.key',7);
keystr = EncryptionUtil.joinLines(keyln,totlines,2,1); % key string
publicKey = EncryptionUtil.convertSSHPublicKey(keystr, keyFactory); % convert key
% read private OpenSSH key
[keyln, totlines] = EncryptionUtil.readJschKeyFile('keys/privateJsch.key');
keystr = EncryptionUtil.joinLines(keyln,totlines,1,1); % key string
privateKey = EncryptionUtil.convertSSHPrivateKey(keystr, keyFactory); % convert key
%% write and compare keys
keyfiles = 'keys/test.key';comment = 'testReadWriteSSHKeyPair';
[publicSSHKey,privateSSHKey] = EncryptionUtil.writeSSHKeys(publicKey,privateKey, ...
keyfiles,comment);
fprintf('\n%s\n%s\n',publicSSHKey,privateSSHKey)
visdiff('keys\privateJsch.key','keys\test.key')
visdiff('keys\publicJschSECSH.key','keys\test.key.pub')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment