# HG changeset patch # User Carl Byington # Date 1675299329 25200 # Node ID 7953570e52109b3bd9dd7aed8a84ddf4361b4833 # Parent 2eb4fa13b9efbfa5b935d6441bb392ea8c72ad27 update to ganymed-ssh2 tag 263 and fix hmac-sha2-512 diff -r 2eb4fa13b9ef -r 7953570e5210 TODO --- a/TODO Sun Jan 29 10:25:21 2023 -0700 +++ b/TODO Wed Feb 01 17:55:29 2023 -0700 @@ -81,16 +81,19 @@ ================================== -TODO: +2023-02-01 - 5250 ssl uses javax.net.ssl with security providers, so +that automatically gets better with modern android releases. Remove +SSLv2 and SSLv3, add TLSv1.2 and TLSv1.3 -5250 ssl uses javax.net.ssl with security providers, so that -automatically gets better with modern android releases. Remove -SSLv2 and SSLv3, change to TLSv1.2 and TLSv1.3 +update Ganymed to https://github.com/SoftwareAG/ganymed-ssh-2 tag +ganymed-ssh2-263, with stronger algorithms for message authentication +and key exchange. -ssh uses encryption and signature algorithms from bouncycastle. -Verify those. +================================== +TODO + change all System.*.println -> android Log.d(TAG, "") calls possible move to https://github.com/hierynomus/sshj diff -r 2eb4fa13b9ef -r 7953570e5210 app/src/main/java/ch/ethz/ssh2/Connection.java --- a/app/src/main/java/ch/ethz/ssh2/Connection.java Sun Jan 29 10:25:21 2023 -0700 +++ b/app/src/main/java/ch/ethz/ssh2/Connection.java Wed Feb 01 17:55:29 2023 -0700 @@ -1242,14 +1242,55 @@ } /** + * Removes duplicates from a String array, keeps only first occurence + * of each element. Does not destroy order of elements; can handle nulls. + * Uses a very efficient O(N^2) algorithm =) + * + * @param list a String array. + * @return a cleaned String array. + */ + private String[] removeDuplicates(String[] list) { + if((list == null) || (list.length < 2)) { + return list; + } + + String[] list2 = new String[list.length]; + + int count = 0; + + for(final String element : list) { + boolean duplicate = false; + for(int j = 0; j < count; j++) { + if(((element == null) && (list2[j] == null)) || ((element != null) && (element.equals(list2[j])))) { + duplicate = true; + break; + } + } + if(duplicate) { + continue; + } + list2[count++] = element; + } + + if(count == list2.length) { + return list2; + } + + String[] tmp = new String[count]; + System.arraycopy(list2, 0, tmp, 0, count); + + return tmp; + } + + /** * Unless you know what you are doing, you will never need this. */ - public synchronized void setClient2ServerCiphers(final String[] ciphers) { + public synchronized void setClient2ServerCiphers(String[] ciphers) { if ((ciphers == null) || (ciphers.length == 0)) { throw new IllegalArgumentException(); } - + ciphers = removeDuplicates(ciphers); BlockCipherFactory.checkCipherList(ciphers); cryptoWishList.c2s_enc_algos = ciphers; } @@ -1258,7 +1299,11 @@ * Unless you know what you are doing, you will never need this. */ - public synchronized void setClient2ServerMACs(final String[] macs) { + public synchronized void setClient2ServerMACs(String[] macs) { + if((macs == null) || (macs.length == 0)) { + throw new IllegalArgumentException(); + } + macs = removeDuplicates(macs); MAC.checkMacList(macs); cryptoWishList.c2s_mac_algos = macs; } @@ -1283,7 +1328,11 @@ * Unless you know what you are doing, you will never need this. */ - public synchronized void setServer2ClientCiphers(final String[] ciphers) { + public synchronized void setServer2ClientCiphers(String[] ciphers) { + if((ciphers == null) || (ciphers.length == 0)) { + throw new IllegalArgumentException(); + } + ciphers = removeDuplicates(ciphers); BlockCipherFactory.checkCipherList(ciphers); cryptoWishList.s2c_enc_algos = ciphers; } @@ -1292,7 +1341,11 @@ * Unless you know what you are doing, you will never need this. */ - public synchronized void setServer2ClientMACs(final String[] macs) { + public synchronized void setServer2ClientMACs(String[] macs) { + if((macs == null) || (macs.length == 0)) { + throw new IllegalArgumentException(); + } + macs = removeDuplicates(macs); MAC.checkMacList(macs); cryptoWishList.s2c_mac_algos = macs; } @@ -1310,12 +1363,36 @@ * at least one entry. */ - public synchronized void setServerHostKeyAlgorithms(final String[] algos) { + public synchronized void setServerHostKeyAlgorithms(String[] algos) { + if ((algos == null) || (algos.length == 0)) { + throw new IllegalArgumentException(); + } + algos = removeDuplicates(algos); KexManager.checkServerHostkeyAlgorithmsList(algos); cryptoWishList.serverHostKeyAlgorithms = algos; } /** + * Define the set of allowed key exchange methods. + * + * @param algos An array of allowed key exchange methods. The following are supported: + * diffie-hellman-group14-sha256, + * diffie-hellman-group16-sha512, + * diffie-hellman-group18-sha512, + * diffie-hellman-group14-sha1, + * diffie-hellman-group1-sha1, + * diffie-hellman-group-exchange-sha1 + */ + public synchronized void setClientKexAlgorithms(String[] algos) { + if ((algos == null) || (algos.length == 0)) { + throw new IllegalArgumentException(); + } + algos = removeDuplicates(algos); + KexManager.checkClientKexAlgorithmList(algos); + cryptoWishList.kexAlgorithms = algos; + } + + /** * Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm) on the underlying socket. *

* Can be called at any time. If the connection has not yet been established diff -r 2eb4fa13b9ef -r 7953570e5210 app/src/main/java/ch/ethz/ssh2/KnownHosts.java --- a/app/src/main/java/ch/ethz/ssh2/KnownHosts.java Sun Jan 29 10:25:21 2023 -0700 +++ b/app/src/main/java/ch/ethz/ssh2/KnownHosts.java Wed Feb 01 17:55:29 2023 -0700 @@ -180,7 +180,7 @@ } try { - HMAC hmac = new HMAC(sha1, salt, salt.length); + HMAC hmac = new HMAC(sha1, salt, salt.length, 64); hmac.update(StringEncoder.GetBytes(hostname)); byte[] dig = new byte[hmac.getDigestLength()]; hmac.digest(dig); diff -r 2eb4fa13b9ef -r 7953570e5210 app/src/main/java/ch/ethz/ssh2/crypto/digest/HMAC.java --- a/app/src/main/java/ch/ethz/ssh2/crypto/digest/HMAC.java Sun Jan 29 10:25:21 2023 -0700 +++ b/app/src/main/java/ch/ethz/ssh2/crypto/digest/HMAC.java Wed Feb 01 17:55:29 2023 -0700 @@ -21,15 +21,14 @@ int size; - public HMAC(Digest md, byte[] key, int size) throws DigestException { + public HMAC(Digest md, byte[] key, int digestsize, int blocksize) throws DigestException { this.md = md; - this.size = size; + this.size = digestsize; tmp = new byte[md.getDigestLength()]; - final int BLOCKSIZE = 64; - k_xor_ipad = new byte[BLOCKSIZE]; - k_xor_opad = new byte[BLOCKSIZE]; + k_xor_ipad = new byte[blocksize]; + k_xor_opad = new byte[blocksize]; - if (key.length > BLOCKSIZE) { + if (key.length > blocksize) { md.reset(); md.update(key); md.digest(tmp); @@ -39,7 +38,7 @@ System.arraycopy(key, 0, k_xor_ipad, 0, key.length); System.arraycopy(key, 0, k_xor_opad, 0, key.length); - for (int i = 0; i < BLOCKSIZE; i++) { + for (int i = 0; i < blocksize; i++) { k_xor_ipad[i] ^= 0x36; k_xor_opad[i] ^= 0x5C; } diff -r 2eb4fa13b9ef -r 7953570e5210 app/src/main/java/ch/ethz/ssh2/crypto/digest/MAC.java --- a/app/src/main/java/ch/ethz/ssh2/crypto/digest/MAC.java Sun Jan 29 10:25:21 2023 -0700 +++ b/app/src/main/java/ch/ethz/ssh2/crypto/digest/MAC.java Wed Feb 01 17:55:29 2023 -0700 @@ -20,7 +20,7 @@ public static String[] getMacList() { // Higher priority (stronger) first. Added SHA-2 algorithms as in RFC 6668 return new String[] { - // "hmac-sha2-512", // fails interop w/ centos6 + "hmac-sha2-512", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", @@ -36,51 +36,33 @@ } public static int getKeyLen(final String type) { - if (type.equals("hmac-sha1")) { - return 20; - } - - if (type.equals("hmac-sha1-96")) { - return 20; - } - - if (type.equals("hmac-md5")) { - return 16; - } - - if (type.equals("hmac-md5-96")) { - return 16; - } - - if (type.equals("hmac-sha2-256")) { - return 32; - } - - if (type.equals("hmac-sha2-512")) { - return 64; - } - + if (type.equals("hmac-sha2-512")) return 64; + if (type.equals("hmac-sha2-256")) return 32; + if (type.equals("hmac-sha1")) return 20; + if (type.equals("hmac-sha1-96")) return 20; + if (type.equals("hmac-md5")) return 16; + if (type.equals("hmac-md5-96")) return 16; throw new IllegalArgumentException(String.format("Unknown algorithm %s", type)); } public MAC(final String type, final byte[] key) throws DigestException { - if (type.equals("hmac-sha1")) { - mac = new HMAC(new SHA1(), key, 20); + if (type.equals("hmac-sha2-512")) { + mac = new HMAC(new SHA512(), key, 64, 128); + } + else if (type.equals("hmac-sha2-256")) { + mac = new HMAC(new SHA256(), key, 32, 64); + } + else if (type.equals("hmac-sha1")) { + mac = new HMAC(new SHA1(), key, 20, 64); } else if (type.equals("hmac-sha1-96")) { - mac = new HMAC(new SHA1(), key, 12); + mac = new HMAC(new SHA1(), key, 12, 64); } else if (type.equals("hmac-md5")) { - mac = new HMAC(new MD5(), key, 16); + mac = new HMAC(new MD5(), key, 16, 64); } else if (type.equals("hmac-md5-96")) { - mac = new HMAC(new MD5(), key, 12); - } - else if (type.equals("hmac-sha2-256")) { - mac = new HMAC(new SHA256(), key, 32); - } - else if (type.equals("hmac-sha2-512")) { - mac = new HMAC(new SHA512(), key, 64); + mac = new HMAC(new MD5(), key, 12, 64); } else { throw new IllegalArgumentException(String.format("Unknown algorithm %s", type)); diff -r 2eb4fa13b9ef -r 7953570e5210 app/src/main/java/ch/ethz/ssh2/crypto/digest/SHA512.java --- a/app/src/main/java/ch/ethz/ssh2/crypto/digest/SHA512.java Sun Jan 29 10:25:21 2023 -0700 +++ b/app/src/main/java/ch/ethz/ssh2/crypto/digest/SHA512.java Wed Feb 01 17:55:29 2023 -0700 @@ -33,7 +33,7 @@ } public final void update(byte b[]) { - md.update(b); + this.update(b, 0, b.length); } public final void update(byte b[], int off, int len) { @@ -44,11 +44,11 @@ md.update(b); } - public final void digest(byte[] out) { - md.digest(out); + public final void digest(byte[] out) throws DigestException { + this.digest(out, 0); } public final void digest(byte[] out, int off) throws DigestException { - md.digest(out, off, out.length); + md.digest(out, off, out.length - off); } } diff -r 2eb4fa13b9ef -r 7953570e5210 app/src/main/java/ch/ethz/ssh2/transport/ClientKexManager.java --- a/app/src/main/java/ch/ethz/ssh2/transport/ClientKexManager.java Sun Jan 29 10:25:21 2023 -0700 +++ b/app/src/main/java/ch/ethz/ssh2/transport/ClientKexManager.java Wed Feb 01 17:55:29 2023 -0700 @@ -161,6 +161,9 @@ if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1") || kxs.np.kex_algo.equals("diffie-hellman-group14-sha1") || + kxs.np.kex_algo.equals("diffie-hellman-group14-sha256") || + kxs.np.kex_algo.equals("diffie-hellman-group16-sha512") || + kxs.np.kex_algo.equals("diffie-hellman-group18-sha512") || kxs.np.kex_algo.equals("ecdh-sha2-nistp256") || kxs.np.kex_algo.equals("ecdh-sha2-nistp384") || kxs.np.kex_algo.equals("ecdh-sha2-nistp521")) { @@ -282,6 +285,9 @@ if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1") || kxs.np.kex_algo.equals("diffie-hellman-group14-sha1") || + kxs.np.kex_algo.equals("diffie-hellman-group14-sha256") || + kxs.np.kex_algo.equals("diffie-hellman-group16-sha512") || + kxs.np.kex_algo.equals("diffie-hellman-group18-sha512") || kxs.np.kex_algo.equals("ecdh-sha2-nistp256") || kxs.np.kex_algo.equals("ecdh-sha2-nistp384") || kxs.np.kex_algo.equals("ecdh-sha2-nistp521")) { diff -r 2eb4fa13b9ef -r 7953570e5210 app/src/main/java/ch/ethz/ssh2/transport/KexManager.java --- a/app/src/main/java/ch/ethz/ssh2/transport/KexManager.java Sun Jan 29 10:25:21 2023 -0700 +++ b/app/src/main/java/ch/ethz/ssh2/transport/KexManager.java Wed Feb 01 17:55:29 2023 -0700 @@ -52,6 +52,9 @@ KEX_ALGS.add("diffie-hellman-group-exchange-sha256"); KEX_ALGS.add("diffie-hellman-group-exchange-sha1"); KEX_ALGS.add("diffie-hellman-group14-sha1"); + KEX_ALGS.add("diffie-hellman-group14-sha256"); + KEX_ALGS.add("diffie-hellman-group16-sha512"); + KEX_ALGS.add("diffie-hellman-group18-sha512"); KEX_ALGS.add("diffie-hellman-group1-sha1"); KEX_ALGS.add("ecdh-sha2-nistp256"); KEX_ALGS.add("ecdh-sha2-nistp384"); @@ -295,7 +298,7 @@ return KEX_ALGS.toArray(new String[KEX_ALGS.size()]); } - public static void checkKexAlgorithmList(String[] algos) { + public static void checkClientKexAlgorithmList(String[] algos) { for (final String algo : algos) { if (!KEX_ALGS.contains(algo)) throw new IllegalArgumentException("Unknown kex algorithm '" + algo + "'");