Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JENKINS-62552] Use standard crypto APIs #45

Merged
merged 3 commits into from
Jul 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
102 changes: 52 additions & 50 deletions src/com/trilead/ssh2/crypto/PEMDecoder.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@

package com.trilead.ssh2.crypto;

import com.trilead.ssh2.crypto.cipher.JreCipherWrapper;
import com.trilead.ssh2.signature.DSAPrivateKey;
import com.trilead.ssh2.signature.KeyAlgorithm;
import com.trilead.ssh2.signature.KeyAlgorithmManager;
import com.trilead.ssh2.signature.RSAPrivateKey;

import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.io.BufferedReader;
import java.io.CharArrayReader;
import java.io.IOException;
import java.math.BigInteger;
import java.security.DigestException;
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.trilead.ssh2.crypto.cipher.AES;
import com.trilead.ssh2.crypto.cipher.BlockCipher;
import com.trilead.ssh2.crypto.cipher.CBCMode;
import com.trilead.ssh2.crypto.cipher.DES;
import com.trilead.ssh2.crypto.cipher.DESede;
import com.trilead.ssh2.crypto.digest.MD5;
import com.trilead.ssh2.signature.DSAPrivateKey;
import com.trilead.ssh2.signature.KeyAlgorithm;
import com.trilead.ssh2.signature.KeyAlgorithmManager;
import com.trilead.ssh2.signature.RSAPrivateKey;

/**
* PEM Support.
*
Expand Down Expand Up @@ -73,13 +73,21 @@ private static byte[] hexToByteArray(String hex)
return decoded;
}

/**
* @deprecated Use PBE ciphers
*/
public static byte[] generateKeyFromPasswordSaltWithMD5(byte[] password, byte[] salt, int keyLen)
throws IOException
{
if (salt.length < 8)
throw new IllegalArgumentException("Salt needs to be at least 8 bytes for key generation.");

MD5 md5 = new MD5();
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException(e);
}

byte[] key = new byte[keyLen];
byte[] tmp = new byte[md5.getDigestLength()];
Expand All @@ -93,7 +101,11 @@ public static byte[] generateKeyFromPasswordSaltWithMD5(byte[] password, byte[]

int copy = (keyLen < tmp.length) ? keyLen : tmp.length;

md5.digest(tmp, 0);
try {
md5.digest(tmp, 0, tmp.length);
} catch (DigestException e) {
throw new IllegalArgumentException(e);
}

System.arraycopy(tmp, 0, key, key.length - keyLen, copy);

Expand Down Expand Up @@ -323,7 +335,7 @@ private static PEMStructure parsePEM(char[] pem, CertificateDecoder certificateD
return ps;
}

private static void decryptPEM(PEMStructure ps, byte[] pw) throws IOException
private static void decryptPEM(PEMStructure ps, char[] pw) throws IOException
kuisathaverat marked this conversation as resolved.
Show resolved Hide resolved
{
if (ps.dekInfo == null)
throw new IOException("Broken PEM, no mode and salt given, but encryption enabled");
Expand All @@ -334,41 +346,31 @@ private static void decryptPEM(PEMStructure ps, byte[] pw) throws IOException
String algo = ps.dekInfo[0];
byte[] salt = hexToByteArray(ps.dekInfo[1]);

BlockCipher bc;
JreCipherWrapper bc;

if (algo.equals("DES-EDE3-CBC"))
{
DESede des3 = new DESede();
des3.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 24));
bc = new CBCMode(des3, salt, false);
}
else if (algo.equals("DES-CBC"))
{
DES des = new DES();
des.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 8));
bc = new CBCMode(des, salt, false);
}
else if (algo.equals("AES-128-CBC"))
{
AES aes = new AES();
aes.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 16));
bc = new CBCMode(aes, salt, false);
}
else if (algo.equals("AES-192-CBC"))
{
AES aes = new AES();
aes.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 24));
bc = new CBCMode(aes, salt, false);
}
else if (algo.equals("AES-256-CBC"))
{
AES aes = new AES();
aes.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 32));
bc = new CBCMode(aes, salt, false);
}
else
{
throw new IOException("Cannot decrypt PEM structure, unknown cipher " + algo);
switch (algo) {
case "DES-EDE3-CBC":
bc = JreCipherWrapper.getInstance("PBEWithMD5AndDESede", new PBEParameterSpec(salt, 1));
bc.init(false, new PBEKeySpec(pw, salt, 1, 24));
break;
case "DES-CBC":
bc = JreCipherWrapper.getInstance("PBEWithMD5AndDES", new PBEParameterSpec(salt, 1));
bc.init(false, new PBEKeySpec(pw, salt, 1, 8));
break;
case "AES-128-CBC":
bc = JreCipherWrapper.getInstance("PBEWithMD5AndAES_128", new PBEParameterSpec(salt, 1));
bc.init(false, new PBEKeySpec(pw, salt, 1,16));
break;
case "AES-192-CBC":
bc = JreCipherWrapper.getInstance("PBEWithMD5AndAES_192", new PBEParameterSpec(salt, 1));
bc.init(false, new PBEKeySpec(pw, salt, 1, 24));
break;
case "AES-256-CBC":
bc = JreCipherWrapper.getInstance("PBEWithMD5AndAES_256", new PBEParameterSpec(salt, 1));
bc.init(false, new PBEKeySpec(pw, salt, 1, 32));
break;
default:
throw new IOException("Cannot decrypt PEM structure, unknown cipher " + algo);
}

if ((ps.data.length % bc.getBlockSize()) != 0)
Expand Down Expand Up @@ -417,7 +419,7 @@ public static Object decode(char[] pem, String password) throws IOException
if (password == null)
throw new IOException("PEM is encrypted, but no password was specified");

decryptPEM(ps, password.getBytes("ISO-8859-1"));
decryptPEM(ps, password.toCharArray());
kuisathaverat marked this conversation as resolved.
Show resolved Hide resolved
}

if (ps.pemType == PEM_DSA_PRIVATE_KEY)
Expand Down Expand Up @@ -487,7 +489,7 @@ public static KeyPair decodeKeyPair(char[] pem, String password) throws IOExcept
if (password == null)
throw new IOException("PEM is encrypted, but no password was specified");

decryptPEM(ps, password.getBytes("ISO-8859-1"));
decryptPEM(ps, password.toCharArray());
kuisathaverat marked this conversation as resolved.
Show resolved Hide resolved
}

return decoder.createKeyPair(ps, password);
Expand Down
2 changes: 2 additions & 0 deletions src/com/trilead/ssh2/crypto/cipher/AES.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ of this software and associated documentation files (the "Software"), to deal
*
* @author See comments in the source file
* @version $Id: AES.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $
* @deprecated Use {@link javax.crypto.Cipher} instead.
* See <a href="https://issues.jenkins-ci.org/browse/JENKINS-62552">JENKINS-62552</a>.
*/
public class AES implements BlockCipher
{
Expand Down
63 changes: 23 additions & 40 deletions src/com/trilead/ssh2/crypto/cipher/BlockCipherFactory.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

package com.trilead.ssh2.crypto.cipher;

import javax.crypto.spec.IvParameterSpec;
import java.util.Vector;

/**
Expand All @@ -14,46 +15,46 @@ public class BlockCipherFactory
static class CipherEntry
{
String type;
String algorithm;
int blocksize;
int keysize;
String cipherClass;

public CipherEntry(String type, int blockSize, int keySize, String cipherClass)
public CipherEntry(String type, String algorithm, int blockSize, int keySize)
{
this.type = type;
this.algorithm = algorithm;
this.blocksize = blockSize;
this.keysize = keySize;
this.cipherClass = cipherClass;
}
}

static Vector ciphers = new Vector();
static Vector<CipherEntry> ciphers = new Vector<>();

static
{
/* Higher Priority First */

ciphers.addElement(new CipherEntry("aes256-ctr", 16, 32, "com.trilead.ssh2.crypto.cipher.AES"));
ciphers.addElement(new CipherEntry("aes192-ctr", 16, 24, "com.trilead.ssh2.crypto.cipher.AES"));
ciphers.addElement(new CipherEntry("aes128-ctr", 16, 16, "com.trilead.ssh2.crypto.cipher.AES"));
ciphers.addElement(new CipherEntry("blowfish-ctr", 8, 16, "com.trilead.ssh2.crypto.cipher.BlowFish"));
ciphers.addElement(new CipherEntry("aes256-ctr", "AES/CTR/NoPadding", 16, 32));
ciphers.addElement(new CipherEntry("aes192-ctr", "AES/CTR/NoPadding", 16, 24));
ciphers.addElement(new CipherEntry("aes128-ctr", "AES/CTR/NoPadding", 16, 16));
ciphers.addElement(new CipherEntry("blowfish-ctr", "Blowfish/CTR/NoPadding", 8, 16));

ciphers.addElement(new CipherEntry("aes256-cbc", 16, 32, "com.trilead.ssh2.crypto.cipher.AES"));
ciphers.addElement(new CipherEntry("aes192-cbc", 16, 24, "com.trilead.ssh2.crypto.cipher.AES"));
ciphers.addElement(new CipherEntry("aes128-cbc", 16, 16, "com.trilead.ssh2.crypto.cipher.AES"));
ciphers.addElement(new CipherEntry("blowfish-cbc", 8, 16, "com.trilead.ssh2.crypto.cipher.BlowFish"));
ciphers.addElement(new CipherEntry("aes256-cbc", "AES/CBC/NoPadding", 16, 32));
ciphers.addElement(new CipherEntry("aes192-cbc", "AES/CBC/NoPadding", 16, 24));
ciphers.addElement(new CipherEntry("aes128-cbc", "AES/CBC/NoPadding", 16, 16));
ciphers.addElement(new CipherEntry("blowfish-cbc", "Blowfish/CBC/NoPadding", 8, 16));

ciphers.addElement(new CipherEntry("3des-ctr", 8, 24, "com.trilead.ssh2.crypto.cipher.DESede"));
ciphers.addElement(new CipherEntry("3des-cbc", 8, 24, "com.trilead.ssh2.crypto.cipher.DESede"));
ciphers.addElement(new CipherEntry("3des-ctr", "DESede/CTR/NoPadding", 8, 24));
ciphers.addElement(new CipherEntry("3des-cbc", "DESede/CBC/NoPadding", 8, 24));
}

public static String[] getDefaultCipherList()
{
String list[] = new String[ciphers.size()];
String[] list = new String[ciphers.size()];
for (int i = 0; i < ciphers.size(); i++)
{
CipherEntry ce = (CipherEntry) ciphers.elementAt(i);
list[i] = new String(ce.type);
CipherEntry ce = ciphers.elementAt(i);
list[i] = ce.type;
}
return list;
}
Expand All @@ -66,35 +67,17 @@ public static void checkCipherList(String[] cipherCandidates)

public static BlockCipher createCipher(String type, boolean encrypt, byte[] key, byte[] iv)
{
try
{
CipherEntry ce = getEntry(type);
Class cc = Class.forName(ce.cipherClass);
BlockCipher bc = (BlockCipher) cc.newInstance();

if (type.endsWith("-cbc"))
{
bc.init(encrypt, key);
return new CBCMode(bc, iv, encrypt);
}
else if (type.endsWith("-ctr"))
{
bc.init(true, key);
return new CTRMode(bc, iv, encrypt);
}
throw new IllegalArgumentException("Cannot instantiate " + type);
}
catch (Exception e)
{
throw new IllegalArgumentException("Cannot instantiate " + type);
}
CipherEntry ce = getEntry(type);
BlockCipher bc = JreCipherWrapper.getInstance(ce.algorithm, new IvParameterSpec(iv));
bc.init(encrypt, key);
return bc;
}

private static CipherEntry getEntry(String type)
{
for (int i = 0; i < ciphers.size(); i++)
{
CipherEntry ce = (CipherEntry) ciphers.elementAt(i);
CipherEntry ce = ciphers.elementAt(i);
if (ce.type.equals(type))
return ce;
}
Expand Down
2 changes: 2 additions & 0 deletions src/com/trilead/ssh2/crypto/cipher/BlowFish.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ of this software and associated documentation files (the "Software"), to deal
*
* @author See comments in the source file
* @version $Id: BlowFish.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $
* @deprecated Use {@link javax.crypto.Cipher} instead.
* See <a href="https://issues.jenkins-ci.org/browse/JENKINS-62552">JENKINS-62552</a>.
*/
public class BlowFish implements BlockCipher
{
Expand Down
2 changes: 2 additions & 0 deletions src/com/trilead/ssh2/crypto/cipher/CBCMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
*
* @author Christian Plattner, plattner@trilead.com
* @version $Id: CBCMode.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $
* @deprecated Use {@link javax.crypto.Cipher} with the {@code CBC} transformation mode instead.
* See <a href="https://issues.jenkins-ci.org/browse/JENKINS-62552">JENKINS-62552</a>.
*/
public class CBCMode implements BlockCipher
{
Expand Down
2 changes: 2 additions & 0 deletions src/com/trilead/ssh2/crypto/cipher/CTRMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*
* @author Christian Plattner, plattner@trilead.com
* @version $Id: CTRMode.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $
* @deprecated Use {@link javax.crypto.Cipher} with the {@code CTR} transformation mode instead.
* See <a href="https://issues.jenkins-ci.org/browse/JENKINS-62552">JENKINS-62552</a>.
*/
public class CTRMode implements BlockCipher
{
Expand Down
3 changes: 2 additions & 1 deletion src/com/trilead/ssh2/crypto/cipher/DES.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ of this software and associated documentation files (the "Software"), to deal
*
* @author See comments in the source file
* @version $Id: DES.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $
*
* @deprecated Nobody should still be using DES for encryption. Use {@link javax.crypto.Cipher} instead for decryption.
* See <a href="https://issues.jenkins-ci.org/browse/JENKINS-62552">JENKINS-62552</a>.
*/
public class DES implements BlockCipher
{
Expand Down
3 changes: 2 additions & 1 deletion src/com/trilead/ssh2/crypto/cipher/DESede.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ of this software and associated documentation files (the "Software"), to deal
*
* @author See comments in the source file
* @version $Id: DESede.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $
*
* @deprecated Use {@link javax.crypto.Cipher} instead.
* See <a href="https://issues.jenkins-ci.org/browse/JENKINS-62552">JENKINS-62552</a>.
*/
public class DESede extends DES
{
Expand Down
Loading