Skip to content

Commit

Permalink
add support for hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@opens…
Browse files Browse the repository at this point in the history
…sh.com in trilead-ssh2 org. impl. Kenny Root (#93)

Co-authored-by: mikael petterson <mikael.petterson@ericsson.com>
  • Loading branch information
mpet and eraonel committed Jul 4, 2022
1 parent 7146018 commit 546f979
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 108 deletions.
83 changes: 36 additions & 47 deletions src/com/trilead/ssh2/crypto/cipher/CipherInputStream.java
@@ -1,65 +1,33 @@

package com.trilead.ssh2.crypto.cipher;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
* CipherInputStream.
*
*
* @author Christian Plattner, plattner@trilead.com
* @version $Id: CipherInputStream.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $
*/
public class CipherInputStream
{
BlockCipher currentCipher;
InputStream bi;
byte[] buffer;
byte[] enc;
int blockSize;
int pos;

/*
* We cannot use java.io.BufferedInputStream, since that is not available in
* J2ME. Everything could be improved alot here.
*/

final int BUFF_SIZE = 2048;
byte[] input_buffer = new byte[BUFF_SIZE];
int input_buffer_pos = 0;
int input_buffer_size = 0;
private BlockCipher currentCipher;
private final BufferedInputStream bi;
private byte[] buffer;
private byte[] enc;
private int blockSize;
private int pos;

public CipherInputStream(BlockCipher tc, InputStream bi)
{
this.bi = bi;
changeCipher(tc);
}

private int fill_buffer() throws IOException
{
input_buffer_pos = 0;
input_buffer_size = bi.read(input_buffer, 0, BUFF_SIZE);
return input_buffer_size;
}

private int internal_read(byte[] b, int off, int len) throws IOException
{
if (input_buffer_size < 0)
return -1;

if (input_buffer_pos >= input_buffer_size)
{
if (fill_buffer() <= 0)
return -1;
if (bi instanceof BufferedInputStream) {
this.bi = (BufferedInputStream) bi;
} else {
this.bi = new BufferedInputStream(bi);
}

int avail = input_buffer_size - input_buffer_pos;
int thiscopy = (len > avail) ? avail : len;

System.arraycopy(input_buffer, input_buffer_pos, b, off, thiscopy);
input_buffer_pos += thiscopy;

return thiscopy;
changeCipher(tc);
}

public void changeCipher(BlockCipher bc)
Expand All @@ -76,7 +44,7 @@ private void getBlock() throws IOException
int n = 0;
while (n < blockSize)
{
int len = internal_read(enc, n, blockSize - n);
int len = bi.read(enc, n, blockSize - n);
if (len < 0)
throw new IOException("Cannot read full block, EOF reached.");
n += len;
Expand Down Expand Up @@ -134,11 +102,32 @@ public int readPlain(byte[] b, int off, int len) throws IOException
int n = 0;
while (n < len)
{
int cnt = internal_read(b, off + n, len - n);
int cnt = bi.read(b, off + n, len - n);
if (cnt < 0)
throw new IOException("Cannot fill buffer, EOF reached.");
n += cnt;
}
return n;
}

public int peekPlain(byte[] b, int off, int len) throws IOException
{
if (pos != blockSize)
throw new IOException("Cannot read plain since crypto buffer is not aligned.");
int n = 0;

bi.mark(len);
try {
while (n < len) {
int cnt = bi.read(b, off + n, len - n);
if (cnt < 0)
throw new IOException("Cannot fill buffer, EOF reached.");
n += cnt;
}
} finally {
bi.reset();
}

return n;
}
}
18 changes: 18 additions & 0 deletions src/com/trilead/ssh2/crypto/cipher/CipherOutputStream.java
@@ -1,6 +1,7 @@

package com.trilead.ssh2.crypto.cipher;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

Expand All @@ -18,6 +19,8 @@ public class CipherOutputStream
byte[] enc;
int blockSize;
int pos;
private boolean recordingOutput;
private final ByteArrayOutputStream recordingOutputStream = new ByteArrayOutputStream();

/*
* We cannot use java.io.BufferedOutputStream, since that is not available
Expand Down Expand Up @@ -86,6 +89,17 @@ public void changeCipher(BlockCipher bc)
enc = new byte[blockSize];
pos = 0;
}

public void startRecording() {
recordingOutput = true;
}

public byte[] getRecordedOutput() {
recordingOutput = false;
byte[] recordedOutput = recordingOutputStream.toByteArray();
recordingOutputStream.reset();
return recordedOutput;
}

private void writeBlock() throws IOException
{
Expand All @@ -100,6 +114,10 @@ private void writeBlock() throws IOException

internal_write(enc, 0, blockSize);
pos = 0;

if (recordingOutput) {
recordingOutputStream.write(enc, 0, blockSize);
}
}

public void write(byte[] src, int off, int len) throws IOException
Expand Down
58 changes: 47 additions & 11 deletions src/com/trilead/ssh2/crypto/digest/MessageMac.java
Expand Up @@ -2,6 +2,7 @@
package com.trilead.ssh2.crypto.digest;

import javax.crypto.Mac;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
Expand All @@ -10,12 +11,27 @@
public final class MessageMac extends MAC {

private final Mac messageMac;
private boolean encryptThenMac = false;
private final byte[] buffer;
private final int outSize;

public MessageMac(String type, byte[] key) {
super(type, key);

try {
messageMac = Mac.getInstance(Hmac.getHmac(type).getAlgorithm());

int macSize = messageMac.getMacLength();

if (type.endsWith("-96")) {
outSize = 12;
buffer = new byte[macSize];
} else {
outSize = macSize;
buffer = null;
}

encryptThenMac = Hmac.getHmac(type).isEtm();
messageMac.init(new SecretKeySpec(key, type));
} catch (GeneralSecurityException ex) {
throw new IllegalArgumentException("Could not create Mac", ex);
Expand Down Expand Up @@ -55,32 +71,48 @@ public final void update(byte[] packetdata, int off, int len)
}

public final void getMac(byte[] out, int off) {
byte[] mac = messageMac.doFinal();
System.arraycopy(mac, off, out, 0, mac.length - off);
try {
if (buffer != null) {
messageMac.doFinal(buffer, 0);
System.arraycopy(buffer, 0, out, off, out.length - off);
} else {
messageMac.doFinal(out, off);
}
} catch (ShortBufferException e) {
throw new IllegalStateException(e);
}
}

public final int size()
{
return messageMac.getMacLength();
return outSize;
}

public final boolean isEncryptThenMac()
{
return encryptThenMac;
}


private enum Hmac {
HMAC_MD5_96("hmac-md5-96", "HmacMD5", 16),
HMAC_MD5("hmac-md5", "HmacMD5", 16),
HMAC_SHA1_96("hmac-sha1-96", "HmacSHA1", 20),
HMAC_SHA1("hmac-sha1", "HmacSHA1", 20),
HMAC_SHA2_256("hmac-sha2-256", "HmacSHA256", 32),
HMAC_SHA2_512("hmac-sha2-512", "HmacSHA512", 64);
HMAC_MD5_96("hmac-md5-96", "HmacMD5", 16,false),
HMAC_MD5("hmac-md5", "HmacMD5", 16,false),
HMAC_SHA1_96("hmac-sha1-96", "HmacSHA1", 20,false),
HMAC_SHA1("hmac-sha1", "HmacSHA1", 20,false),
HMAC_SHA2_256("hmac-sha2-256", "HmacSHA256", 32,false),
HMAC_SHA2_512("hmac-sha2-512", "HmacSHA512", 64,false),
HMAC_SHA2_256_ETM("hmac-sha2-256-etm@openssh.com", "HmacSHA256", 32,true),
HMAC_SHA2_512_ETM("hmac-sha2-512-etm@openssh.com", "HmacSHA512", 64,true);

private String type;
private String algorithm;
private int length;
private boolean isEtm;

Hmac(String type, String algorithm, int length) {
Hmac(String type, String algorithm, int length,boolean isEtm) {
this.type = type;
this.algorithm = algorithm;
this.length = length;
this.isEtm = isEtm;
}

public String getType() {
Expand All @@ -94,6 +126,10 @@ public String getAlgorithm() {
public int getLength() {
return length;
}

public boolean isEtm() {
return isEtm;
}

private static Hmac getHmac(String type) {
for (Hmac hmac : values()) {
Expand Down

0 comments on commit 546f979

Please sign in to comment.