Skip to content

Шифрование методом Диффи-Хеллмана

Синопсис

Метод Диффи-Хеллмана используется для шифрования сообщения передаваемого через незащищенный канал связи. То есть если в кратце то есть среда передачи данных между узлами А и Б, и между ними засел шпион. Этот метод применим только тогда, когда этот шпион может только снимать сигнал из незащищенной среды, но не может выдавать себя за отправителя сообщения А для получателя Б или за отправителя Б для получателя А, в этом случае метод Диффи-Хеллмана не годится, далее будет понятно почему. То есть мы рассматриваем случай, когда шпион вклинивается в канал передачи сообщения и хочет подслушать о чем переговариваются А и Б.

Немного теории

Метод Диффи-Хеллмана позволяет всем участникам общения получить общий секретный ключ (участников может быть два и более) в незащищенной от прослушивания среде. После того как все участники получили свои ключи, каждый из них, используя этот ключ, шифрует свое сообщения используя симметричный алгоритм шифрования для дальнейшего обмена в незащищенном от прослушивания канале. Алгоритм называется симметричным потому что каждый из участников общения использует для шифрования своего сообщения один и тот же ключ. Алгоритм Диффи-Хеллмана позволяет с генерировать этот секретный ключ каждому из участника общения на своей стороне не обмениваясь им через не защищенный канал, однако обмениваться некоторыми исходными параметрами на базе которых секретный ключ будет генерироваться все же придется, поэтому эти исходные параметры не скрываются и передаются в открытом виде, и могут быть доступны шпиону. Так вот, метод Диффи-Хеллмана используется для того, чтоб участники общения А и Б получили один и тот же ключ не обмениваясь им, ведь шпион хочет завладеть именно этим ключом чтобы потом применив его дешифровать перехваченное сообщение. Теперь рассмотрим все по порядку.

Для того чтобы участники А и Б с генерировали одинаковый ключ им должны быть известны исходные параметры на базе которых будет создан секретный ключ. Первые два параметра которые будут известны двум участникам общения А и Б это простые случайные числа p и g. Эти параметры не представляют из себя никакой секретной информации, поэтому они могут передаваться через не защищенный от прослушивания канал в открытом виде, и понято, что они будут известны шпиону.

  1. На первом этапе одна из сторон, допустим это будет сторона А, вычисляет себе числа Latex formula и Latex formula которые будут передаваться стороне Б и некое случайное число Latex formula которое никуда передаваться не будет.
  2. На основе параметров Latex formula, Latex formula и Latex formula сторона А вычисляет параметр Latex formula по формуле Latex formula который так же будет передаваться в открытом виде стороне Б.
  3. Шпион тут же перехватывает параметры Latex formula, Latex formula и Latex formula, а вот параметр Latex formula шпиону не доступен так как он не передается. Но он шпиону не особо то и нужен, так как параметр Latex formula был нужен только для вычисления параметра Latex formula, а ведь его то шпион уже перехватил.
  4. Сторона Б получает те же самые параметры, что перехватил шпион, это Latex formula, Latex formula и Latex formula.
  5. Сторона Б вычисляет закрытый параметр Latex formula который никуда передаваться не будет, а будет нужен только для вычисления открытого параметра Latex formula.
  6. Теперь сторона Б на базе полученных от стороны А параметров и с генерированного числа Latex formula вычисляет открытый параметр Latex formula по формуле Latex formula.
  7. Сторона Б передает стороне А открытый ключ Latex formula
  8. Сторона Б вычисляет секертный ключ Latex formula по формуле Latex formula
  9. Шпион делает все тоже самое, что и сторона Б, вычисляет закрытый параметр Latex formula, и на базе закрытого параметра Latex formula а так же на перехваченных параметрах Latex formula и Latex formula вычисляет открытый параметр Latex formula по формуле Latex formula.
  10. Шпион вычисляет закрытый ключ Latex formula (которым он должен попытаться дешифровать сообщение шифрованное стороной А) по формуле Latex formula
  11. Шпион передает стороне А открытый ключ Latex formula
  12. И тут очень важно стороне А быть очень внимательной, чтобы шпион не ввел ее в заблуждение и не выдал себя стороне А за сторону Б (как это сделать вопрос другой, но если вкратце, то для этого существуют сертификаты). От этого зависит какой параметр сторона А получит (а в дальнейшем на его базе с генерирует секретный ключ), параметр Latex formula от настоящего Б или параметр Latex formula от шпиона.
  13. Допустим, что сторона А проверила паспорт или сертификат который ей предоставила сторона Б, таким образом сторона Б прошла процедуру идентификации на стороне А и сторона А приняла правильный открытый ключ Latex formula от стороны Б, а шпион надеется, что ему удалось всучить свой ключ стороне А.
  14. Сторона А вычисляет секретный ключ Latex formula по формуле Latex formula
  15. На этом этапе все секретный ключи на всех участниках общения готовы, включая шпиона который вычислил секретрный ключ на базе параметров предназначенных для стороны Б.

  16. Так как сторона А приняла открытый ключ Latex formula, а не Latex formula, то закрытый ключ Latex formula на стороне А соответствует закрытому ключу Latex formula на стороне Б, а шпионский ключ Latex formula не соответствует ни одному ни другому.

    Так работает алгоритм Диффи-Хеллмана. А теперь рассмотрим схематично:

    Сторона А Шпион Сторона Б
    Исходное состояние каждого участника Latex formula, Latex formula, Latex formula Latex formula Latex formula
    Сторона А вычисляет открытый параметр Latex formula
    по формуле Latex formula
    Latex formula, Latex formula, Latex formula, Latex formula Latex formula Latex formula
    Сторона А передает параметры Latex formula, Latex formula и Latex formula стороне Б

    Шпион их все перехватывает
    Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula
    Сторона Б вычисляет открытый параметр Latex formula по формуле Latex formula Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula
    Сторона Б вычисляет секеретный ключ Latex formula по формуле Latex formula Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula, Latex formula
    Шпион вычисляет открытый параметр Latex formula по формуле Latex formula Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula, Latex formula
    Шпион вычисляет секеретный ключ Latex formula по формуле Latex formula Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula, Latex formula
    Сторона Б передает открытый ключ Latex formula стороне А Latex formula, Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula, Latex formula
    Шпион передает открытый ключ Latex formula стороне А.
    Сторона А не идентифицурует его как сторону Б (например шпион не предоставил стороне A паспорт или сертификат что он это он) и ключ не принимается
    Latex formula, Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula, Latex formula
    Сторона А генерирует секретный ключ Latex formula на базе полученного параметра Latex formula
    по формуле Latex formula
    Latex formula, Latex formula, Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula, Latex formula Latex formula, Latex formula, Latex formula, Latex formula, Latex formula, Latex formula

    Структура проекта

    Создадим каталог 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(tbl1);
                    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

    Ссылки

    Асимметричное шифрование. Как это работает?

    Поделиться в социальных сетях

    Опубликовать в Google Plus
    Опубликовать в LiveJournal
    Опубликовать в Мой Мир
    Опубликовать в Одноклассники
    Опубликовать в Яндекс

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *