Синопсис
Метод Диффи-Хеллмана используется для шифрования сообщения передаваемого через незащищенный канал связи. То есть если в кратце то есть среда передачи данных между узлами А и Б, и между ними засел шпион. Этот метод применим только тогда, когда этот шпион может только снимать сигнал из незащищенной среды, но не может выдавать себя за отправителя сообщения А для получателя Б или за отправителя Б для получателя А, в этом случае метод Диффи-Хеллмана не годится, далее будет понятно почему. То есть мы рассматриваем случай, когда шпион вклинивается в канал передачи сообщения и хочет подслушать о чем переговариваются А и Б.
Немного теории
Метод Диффи-Хеллмана позволяет всем участникам общения получить общий секретный ключ (участников может быть два и более) в незащищенной от прослушивания среде. После того как все участники получили свои ключи, каждый из них, используя этот ключ, шифрует свое сообщения используя симметричный алгоритм шифрования для дальнейшего обмена в незащищенном от прослушивания канале. Алгоритм называется симметричным потому что каждый из участников общения использует для шифрования своего сообщения один и тот же ключ. Алгоритм Диффи-Хеллмана позволяет с генерировать этот секретный ключ каждому из участника общения на своей стороне не обмениваясь им через не защищенный канал, однако обмениваться некоторыми исходными параметрами на базе которых секретный ключ будет генерироваться все же придется, поэтому эти исходные параметры не скрываются и передаются в открытом виде, и могут быть доступны шпиону. Так вот, метод Диффи-Хеллмана используется для того, чтоб участники общения А и Б получили один и тот же ключ не обмениваясь им, ведь шпион хочет завладеть именно этим ключом чтобы потом применив его дешифровать перехваченное сообщение. Теперь рассмотрим все по порядку.
Для того чтобы участники А и Б с генерировали одинаковый ключ им должны быть известны исходные параметры на базе которых будет создан секретный ключ. Первые два параметра которые будут известны двум участникам общения А и Б это простые случайные числа p и g. Эти параметры не представляют из себя никакой секретной информации, поэтому они могут передаваться через не защищенный от прослушивания канал в открытом виде, и понято, что они будут известны шпиону.
-
На первом этапе одна из сторон, допустим это будет сторона А, вычисляет себе числа
и
которые будут передаваться стороне Б и некое случайное число
которое никуда передаваться не будет.
-
На основе параметров
,
и
сторона А вычисляет параметр
по формуле
который так же будет передаваться в открытом виде стороне Б.
-
Шпион тут же перехватывает параметры
,
и
, а вот параметр
шпиону не доступен так как он не передается. Но он шпиону не особо то и нужен, так как параметр
был нужен только для вычисления параметра
, а ведь его то шпион уже перехватил.
-
Сторона Б получает те же самые параметры, что перехватил шпион, это
,
и
.
-
Сторона Б вычисляет закрытый параметр
который никуда передаваться не будет, а будет нужен только для вычисления открытого параметра
.
-
Теперь сторона Б на базе полученных от стороны А параметров и с генерированного числа
вычисляет открытый параметр
по формуле
.
-
Сторона Б передает стороне А открытый ключ
-
Сторона Б вычисляет секертный ключ
по формуле
-
Шпион делает все тоже самое, что и сторона Б, вычисляет закрытый параметр
, и на базе закрытого параметра
а так же на перехваченных параметрах
и
вычисляет открытый параметр
по формуле
.
-
Шпион вычисляет закрытый ключ
(которым он должен попытаться дешифровать сообщение шифрованное стороной А) по формуле
-
Шпион передает стороне А открытый ключ
-
И тут очень важно стороне А быть очень внимательной, чтобы шпион не ввел ее в заблуждение и не выдал себя стороне А за сторону Б (как это сделать вопрос другой, но если вкратце, то для этого существуют сертификаты). От этого зависит какой параметр сторона А получит (а в дальнейшем на его базе с генерирует секретный ключ), параметр
от настоящего Б или параметр
от шпиона.
-
Допустим, что сторона А проверила паспорт или сертификат который ей предоставила сторона Б, таким образом сторона Б прошла процедуру идентификации на стороне А и сторона А приняла правильный открытый ключ
от стороны Б, а шпион надеется, что ему удалось всучить свой ключ стороне А.
-
Сторона А вычисляет секретный ключ
по формуле
- На этом этапе все секретный ключи на всех участниках общения готовы, включая шпиона который вычислил секретрный ключ на базе параметров предназначенных для стороны Б.
Так как сторона А приняла открытый ключ , а не
, то закрытый ключ
на стороне А соответствует закрытому ключу
на стороне Б, а шпионский ключ
не соответствует ни одному ни другому.
Так работает алгоритм Диффи-Хеллмана. А теперь рассмотрим схематично:
Сторона А | Шпион | Сторона Б | |
Исходное состояние каждого участника |
|
|
|
Сторона А вычисляет открытый параметр |
|
|
|
Сторона А передает параметры Шпион их все перехватывает |
|
|
|
Сторона Б вычисляет открытый параметр |
|
|
|
Сторона Б вычисляет секеретный ключ |
|
|
|
Шпион вычисляет открытый параметр |
|
|
|
Шпион вычисляет секеретный ключ |
|
|
|
Сторона Б передает открытый ключ |
|
|
|
Шпион передает открытый ключ |
|
|
|
Сторона А генерирует секретный ключ |
|
|
|
Структура проекта
Создадим каталог diffie–hellman и в нем создадим такую структуру приложения:
diffie–hellman ├──src │ └─dev │ └─blogs │ └─diffiehellman │ ├─Run.java │ ├─SideA.java │ ├─SideB.java │ ├─Spy.java │ ├─TransportPublicKey.java │ ├─CipherMessage.java │ └─Base64.java └──build.sh
Потом, когда мы добавим все необходимые java файлы и запустим build.sh скрипт, в текущем каталоге появится каталог build, где компилятор разложит каждый класс в свой пакет:
build └──dev └──blogs └──diffiehellman ├─Run.java ├─SideA.java ├─SideB.java ├─Spy.java ├─TransportPublicKey.java ├─CipherMessage.java └─Base64.java
Java код
Run.java
package dev.blogs.diffiehellman; public class Run { public static void main(String [] args) { SideA sideA = new SideA(); SideB sideB = new SideB(); Spy spy = new Spy(); sideA.generateSecretKey(sideB, spy); System.out.println("SideA generates parameters a, p, g and A and sends them to sideB"); System.out.println("Spy intercepts parameters a, p, g and A from sideA and generates privat parameter c"); System.out.println("SideB recieves parameters a, p, g and A from sideA and generates privat parameter b"); System.out.println(); System.out.println("SideB generates key based on parameters p, g, b and A"); System.out.println("SideB send public key B to side A"); System.out.println("Spy intercepts public key B from sideB which oriented for sideA"); System.out.println(); System.out.println("SideA recieves public key B from sideA and generates sercet key based on parameters p, g, a and B"); System.out.println("Spy generates private key as it exchanged sideB base on parameters p, g, c and A"); System.out.println("Spy generates private key as it exchanged sideA base on parameters p, g, c and B"); System.out.println(); System.out.println("Have a look at generated private keys of each participents:"); System.out.print("sideA: "); sideA.showHashSecretKey(); System.out.print("sideB: "); sideB.showHashSecretKey(); System.out.print("spy as it exchanges sideB: "); spy.showHashSecretKey(); System.out.println(); String testMessage = "http://dev-blogs.com"; System.out.println("SideA enciphers message " + testMessage); String encipheredMessage = sideA.encipherMessage(testMessage); System.out.println(); System.out.println("Message was enchiphered and now looks like: " + encipheredMessage); System.out.println(); String decipheredMessage = sideB.decipherMessage(encipheredMessage); System.out.println("SideB deciphers message: " + decipheredMessage); System.out.println(); String decipheredMessageBySpy = spy.decipherMessage(encipheredMessage); System.out.println("Spy deciphers message as it exchanges sideB: " + decipheredMessageBySpy); } }
SideA.java
package dev.blogs.diffiehellman; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.PublicKey; import java.security.SecureRandom; import java.util.Arrays; import javax.crypto.KeyAgreement; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; public class SideA { private byte[] hashSecretKey = null; // The base used with the SKIP 1024 bit modulus private static final BigInteger g = BigInteger.valueOf(2); // The 1024 bit Diffie-Hellman modulus values used by SKIP private static final byte skip1024ModulusBytes[] = { (byte) 0xF4, (byte) 0x88, (byte) 0xFD, (byte) 0x58, (byte) 0x4E, (byte) 0x49, (byte) 0xDB, (byte) 0xCD, (byte) 0x20, (byte) 0xB4, (byte) 0x9D, (byte) 0xE4, (byte) 0x91, (byte) 0x07, (byte) 0x36, (byte) 0x6B, (byte) 0x33, (byte) 0x6C, (byte) 0x38, (byte) 0x0D, (byte) 0x45, (byte) 0x1D, (byte) 0x0F, (byte) 0x7C, (byte) 0x88, (byte) 0xB3, (byte) 0x1C, (byte) 0x7C, (byte) 0x5B, (byte) 0x2D, (byte) 0x8E, (byte) 0xF6, (byte) 0xF3, (byte) 0xC9, (byte) 0x23, (byte) 0xC0, (byte) 0x43, (byte) 0xF0, (byte) 0xA5, (byte) 0x5B, (byte) 0x18, (byte) 0x8D, (byte) 0x8E, (byte) 0xBB, (byte) 0x55, (byte) 0x8C, (byte) 0xB8, (byte) 0x5D, (byte) 0x38, (byte) 0xD3, (byte) 0x34, (byte) 0xFD, (byte) 0x7C, (byte) 0x17, (byte) 0x57, (byte) 0x43, (byte) 0xA3, (byte) 0x1D, (byte) 0x18, (byte) 0x6C, (byte) 0xDE, (byte) 0x33, (byte) 0x21, (byte) 0x2C, (byte) 0xB5, (byte) 0x2A, (byte) 0xFF, (byte) 0x3C, (byte) 0xE1, (byte) 0xB1, (byte) 0x29, (byte) 0x40, (byte) 0x18, (byte) 0x11, (byte) 0x8D, (byte) 0x7C, (byte) 0x84, (byte) 0xA7, (byte) 0x0A, (byte) 0x72, (byte) 0xD6, (byte) 0x86, (byte) 0xC4, (byte) 0x03, (byte) 0x19, (byte) 0xC8, (byte) 0x07, (byte) 0x29, (byte) 0x7A, (byte) 0xCA, (byte) 0x95, (byte) 0x0C, (byte) 0xD9, (byte) 0x96, (byte) 0x9F, (byte) 0xAB, (byte) 0xD0, (byte) 0x0A, (byte) 0x50, (byte) 0x9B, (byte) 0x02, (byte) 0x46, (byte) 0xD3, (byte) 0x08, (byte) 0x3D, (byte) 0x66, (byte) 0xA4, (byte) 0x5D, (byte) 0x41, (byte) 0x9F, (byte) 0x9C, (byte) 0x7C, (byte) 0xBD, (byte) 0x89, (byte) 0x4B, (byte) 0x22, (byte) 0x19, (byte) 0x26, (byte) 0xBA, (byte) 0xAB, (byte) 0xA2, (byte) 0x5E, (byte) 0xC3, (byte) 0x55, (byte) 0xE9, (byte) 0x2F, (byte) 0x78, (byte) 0xC7 }; // The SKIP 1024 bit modulus private static final BigInteger p = new BigInteger(1, skip1024ModulusBytes); public void showHashSecretKey() { for (int i = 0; i < hashSecretKey.length; i++) { System.out.print(hashSecretKey[i] + " "); } System.out.println(); } public void generateSecretKey(SideB sideB, Spy spy) { try { DHParameterSpec dhParams = new DHParameterSpec(p, g); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH"); keyGen.initialize(dhParams, new SecureRandom()); KeyAgreement keyAgree = KeyAgreement.getInstance("DH"); KeyPair pair = keyGen.generateKeyPair(); keyAgree.init(pair.getPrivate()); PublicKey A = pair.getPublic(); String pAsValueAsHexBase64 = CipherMessage.convertBigIntegerToBase64HexString(p); String gAsValueAsHexBase64 = CipherMessage.convertBigIntegerToBase64HexString(g); String yAsValueAsHexBase64 = CipherMessage.convertBigIntegerToBase64HexString(((DHPublicKey) A).getY()); String bKeyAsHexStringBase64 = sideB.generateSecretKey(pAsValueAsHexBase64, gAsValueAsHexBase64, yAsValueAsHexBase64); // spy intercepts parameters p, g, A and B spy.generateSecretKey(pAsValueAsHexBase64, gAsValueAsHexBase64, yAsValueAsHexBase64); BigInteger y = CipherMessage.convertBase64HexStringToBigInteger(bKeyAsHexStringBase64); PublicKey B = TransportPublicKey.getKey(null, y, p, g, 0); keyAgree.doPhase(B, true); byte[] secretKey = keyAgree.generateSecret(); MessageDigest hash = MessageDigest.getInstance("SHA-256"); hashSecretKey = hash.digest(secretKey); hashSecretKey = Arrays.copyOf(hashSecretKey, 16); } catch (Exception e) { e.printStackTrace(); } } public String encipherMessage(String message) { return Base64.encode( CipherMessage.encodeMessage(hashSecretKey, message)); } public String decipherMessage(String encipheredMessage) { String decryptedMessage = null; try { decryptedMessage = CipherMessage.decodeMessage(hashSecretKey, Base64.decode(encipheredMessage)); } catch (javax.crypto.BadPaddingException e) { decryptedMessage = "Message can not be deciphered"; } return decryptedMessage; } }
SideB.java
package dev.blogs.diffiehellman; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.PublicKey; import java.security.SecureRandom; import java.util.Arrays; import javax.crypto.KeyAgreement; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; public class SideB { private byte[] hashSecretKey = null; public void showHashSecretKey() { for (int i = 0; i < hashSecretKey.length; i++) { System.out.print(hashSecretKey[i] + " "); } System.out.println(); } public String generateSecretKey(String pValueAsHexBase64, String gValueAsHexBase64, String publicKeyAsAsHexStringBase64) { BigInteger p = CipherMessage.convertBase64HexStringToBigInteger(pValueAsHexBase64); BigInteger g = CipherMessage.convertBase64HexStringToBigInteger(gValueAsHexBase64); BigInteger y = CipherMessage.convertBase64HexStringToBigInteger(publicKeyAsAsHexStringBase64); PublicKey publicKey = TransportPublicKey.getKey(null, y, p, g, 0); PublicKey key = null; try { DHParameterSpec dhParams = new DHParameterSpec(p, g); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH"); keyGen.initialize(dhParams, new SecureRandom()); KeyAgreement keyAgree = KeyAgreement.getInstance("DH"); KeyPair pair = keyGen.generateKeyPair(); keyAgree.init(pair.getPrivate()); key = pair.getPublic(); keyAgree.doPhase(publicKey, true); byte[] secretKey = keyAgree.generateSecret(); MessageDigest hash = MessageDigest.getInstance("SHA-256"); hashSecretKey = hash.digest(secretKey); hashSecretKey = Arrays.copyOf(hashSecretKey, 16); } catch (Exception e) { e.printStackTrace(); } return CipherMessage.convertBigIntegerToBase64HexString(((DHPublicKey) key).getY()); } public String encipherMessage(String message) { return Base64.encode( CipherMessage.encodeMessage(hashSecretKey, message)); } public String decipherMessage(String encipheredMessage) { String decryptedMessage = null; try { decryptedMessage = CipherMessage.decodeMessage(hashSecretKey, Base64.decode(encipheredMessage)); } catch (javax.crypto.BadPaddingException e) { decryptedMessage = "Message can not be deciphered"; } return decryptedMessage; } }
Spy.java
package dev.blogs.diffiehellman; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.PublicKey; import java.security.SecureRandom; import java.util.Arrays; import javax.crypto.KeyAgreement; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; public class Spy { private byte[] hashSecretKey = null; public void showHashSecretKey() { for (int i = 0; i < hashSecretKey.length; i++) { System.out.print(hashSecretKey[i] + " "); } System.out.println(); } public String generateSecretKey(String pValueAsHexBase64, String gValueAsHexBase64, String publicKeyAsAsHexStringBase64) { BigInteger p = CipherMessage.convertBase64HexStringToBigInteger(pValueAsHexBase64); BigInteger g = CipherMessage.convertBase64HexStringToBigInteger(gValueAsHexBase64); BigInteger y = CipherMessage.convertBase64HexStringToBigInteger(publicKeyAsAsHexStringBase64); PublicKey A = TransportPublicKey.getKey(null, y, p, g, 0); PublicKey key = null; try { DHParameterSpec dhParams = new DHParameterSpec(p, g); KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH"); keyGen.initialize(dhParams, new SecureRandom()); KeyAgreement keyAgree = KeyAgreement.getInstance("DH"); KeyPair pair = keyGen.generateKeyPair(); keyAgree.init(pair.getPrivate()); key = pair.getPublic(); keyAgree.doPhase(A, true); byte[] secretKey = keyAgree.generateSecret(); MessageDigest hash = MessageDigest.getInstance("SHA-256"); hashSecretKey = hash.digest(secretKey); hashSecretKey = Arrays.copyOf(hashSecretKey, 16); } catch (Exception e) { e.printStackTrace(); } return CipherMessage.convertBigIntegerToBase64HexString(((DHPublicKey) key).getY()); } public String encipherMessage(String message) { return Base64.encode( CipherMessage.encodeMessage(hashSecretKey, message)); } public String decipherMessage(String encipheredMessage) { String decryptedMessage = null; try { decryptedMessage = CipherMessage.decodeMessage(hashSecretKey, Base64.decode(encipheredMessage)); } catch (javax.crypto.BadPaddingException e) { decryptedMessage = "Message can not be deciphered"; } return decryptedMessage; } }
TransportPublicKey.java
package dev.blogs.diffiehellman; import java.math.BigInteger; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; public class TransportPublicKey implements DHPublicKey { private byte[] encoded; private BigInteger y; private DHParameterSpec dHParameterSpec; private TransportPublicKey(byte[] encoded, BigInteger y, DHParameterSpec dHParameterSpec) { this.encoded = encoded; this.y = y; this.dHParameterSpec = dHParameterSpec; } public static DHPublicKey getKey(byte[] encoded, BigInteger y, BigInteger p, BigInteger g, int l) { DHParameterSpec dHParameterSpec = new DHParameterSpec(p, g, l); return new TransportPublicKey(encoded, y, dHParameterSpec); } @Override public String getAlgorithm() { return ""; } @Override public String getFormat() { return ""; } @Override public byte[] getEncoded() { return null; } @Override public DHParameterSpec getParams() { return this.dHParameterSpec; } @Override public BigInteger getY() { return this.y; } }
CipherMessage.java
package dev.blogs.diffiehellman; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; public class CipherMessage { public static byte[] encodeMessage(byte[] key, String message) { byte[] encodedMessageAsBytes = null; try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] iv = digest.digest(key); iv = Arrays.copyOf(iv, 16); javax.crypto.spec.SecretKeySpec keyspec = new javax.crypto.spec.SecretKeySpec(key, "AES"); javax.crypto.spec.IvParameterSpec ivspec = new javax.crypto.spec.IvParameterSpec(iv); javax.crypto.Cipher encryptCipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding"); encryptCipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); encodedMessageAsBytes = encryptCipher.doFinal(message.getBytes()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return encodedMessageAsBytes; } public static String decodeMessage(byte[] key, byte[] encodedMessage) throws javax.crypto.BadPaddingException { String value = ""; try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] iv = digest.digest(key); iv = Arrays.copyOf(iv, 16); javax.crypto.spec.SecretKeySpec keyspec = new javax.crypto.spec.SecretKeySpec(key, "AES"); javax.crypto.spec.IvParameterSpec ivspec = new javax.crypto.spec.IvParameterSpec(iv); javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding"); c.init(javax.crypto.Cipher.DECRYPT_MODE, keyspec, ivspec); byte[] decValue = c.doFinal(encodedMessage); value = new String(decValue); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } return value; } private static String convertBigIntegerToString(BigInteger value) { return value.toString(); } private static byte[] convertStringToBytes(String value) { return value.getBytes(); } private static String convertStringToHexString(String value) { return new BigInteger(value).toString(16); } public static String convertBigIntegerToBase64HexString(BigInteger value) { String valueAsString = convertBigIntegerToString(value); String valueAsHexString = convertStringToHexString(valueAsString); return Base64.encode(convertStringToBytes(valueAsHexString)); } private static String convertByteArrayToString(byte[] byteArray) { return new String(byteArray); } private static BigInteger convertStringToBigInteger(String value, int base) { return new BigInteger(value, base); } public static BigInteger convertBase64HexStringToBigInteger(String base64HexString) { byte[] decodedStringAsByteArrayOfHex = Base64.decode(base64HexString); String valueAsHex = convertByteArrayToString(decodedStringAsByteArrayOfHex); return convertStringToBigInteger(valueAsHex, 16); } }
Base64.java
package dev.blogs.diffiehellman; import java.io.ByteArrayOutputStream; public class Base64 { public static String encode(byte[] data) { char[] tbl = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; StringBuilder buffer = new StringBuilder(); int pad = 0; for (int i = 0; i < data.length; i += 3) { int b = ((data[i] & 0xFF) << 16) & 0xFFFFFF; if (i + 1 < data.length) { b |= (data[i + 1] & 0xFF) << 8; } else { pad++; } if (i + 2 < data.length) { b |= (data[i + 2] & 0xFF); } else { pad++; } for (int j = 0; j < 4 - pad; j++) { int c = (b & 0xFC0000) >> 18; buffer.append(tbl); b <<= 6; } } for (int j = 0; j < pad; j++) { buffer.append("="); } return buffer.toString(); } public static byte[] decode(String data) { int[] tbl = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; byte[] bytes = data.getBytes(); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); for (int i = 0; i < bytes.length;) { int b = 0; if (tbl[bytes[i]] != -1) { b = (tbl[bytes[i]] & 0xFF) << 18; } // skip unknown characters else { i++; continue; } int num = 0; if (i + 1 < bytes.length && tbl[bytes[i + 1]] != -1) { b = b | ((tbl[bytes[i + 1]] & 0xFF) << 12); num++; } if (i + 2 < bytes.length && tbl[bytes[i + 2]] != -1) { b = b | ((tbl[bytes[i + 2]] & 0xFF) << 6); num++; } if (i + 3 < bytes.length && tbl[bytes[i + 3]] != -1) { b = b | (tbl[bytes[i + 3]] & 0xFF); num++; } while (num > 0) { int c = (b & 0xFF0000) >> 16; buffer.write((char) c); b <<= 8; num--; } i += 4; } return buffer.toByteArray(); } }
Сборка проекта
Добавляем в корень проекта build.sh скрипт, код которого приводится ниже, назначьте его экзекьютэбл командой:
sudo chmod +x build.sh
И не забываем переделать его в батник, если кто на винде:
build.sh
PATH_TO_PROJECT=`pwd` # Удаляем каталог с предыдущим билдом if test -d $PATH_TO_PROJECT/build; then rm -rf $PATH_TO_PROJECT/build fi # Создаем новый каталог, куда будем помещать билд mkdir $PATH_TO_PROJECT/build # Компилируем проект в каталог build # Для компиляции достаточно библиотеки spring-2.5.5.jar javac -d build src/dev/blogs/diffiehellman/*.java # Выполняем приложение java -cp build dev.blogs.diffiehellman.Run
Готовый проект можно взять на gitHub
Ссылки
Полное руководство по переходу с HTTP на HTTPS
Асимметричное шифрование. Как это работает?