ФЕДЕРАЛЬНОЕ АГЕНТСТВО ЖЕЛЕЗНОДОРОЖНОГО ТРАНСПОРТА Федеральное государственное бюджетное образовательное учреждение высшего образования «Петербургский государственный университет путей сообщения Императора Александра I» (ФГБОУ ВО ПГУПС) Факультет «Автоматизация и интеллектуальные технологии» Кафедра «Информатика и информационная безопасность» Лабораторная работа № 3 по дисциплине «Защита информации» «Реализация функций шифрования и обмена ключами шифрования в программах на языке Java» Выполнил обучающийся Курс 4 Группа ИВБ-711 Н. Д. Яковлев М. Ф. Соломатова Проверил Санкт-Петербург 2022 Оценка лабораторной работы Показатель оценивания Критерии Шкала оценивания оценивания Представленное программное обеспечение работоспособно, 3 выполняет требуемые функции Работоспособность программного обеспечения Программное обеспечение не работоспособно или не 0 выполняет требуемые функции Замечания отсутствуют, либо обнаруженные недостатки устраняются студентом в 2 течение лабораторного занятия, на котором работа представляется к сдаче Замечания к разработанному программному обеспечению Имеются недостатки в результатах работы, не устраненные студентом в день 0 сдачи лабораторной работы (в течение лабораторного занятия) Количество баллов по результатам проверки и защиты лабораторной работы (вписывается преподавателем) 1. Задание 1. Разработать два приложения: приложение-сервер – выполняет функцию генерации и экспортирования ключей алгоритма RSA, а также симметричного шифрования; приложение-клиент – импортирует ключи, генерируемые серверным приложением, расшифровывает сообщение. Примечание. Обмен ключами может производиться путем передачи BLOB через сетевое соединение между компьютерами по локальной сети (используются TCP-сокеты) или через файл на общедоступном диске. 2. Реализовать в приложении-сервере возможность расшифрования (развертки) симметричных ключей на закрытом ключе RSA. 3. Реализовать в приложении-клиенте возможность зашифрования (свертки) симметричных ключей на открытом ключе RSA. 4. В обоих приложениях реализовать функцию симметричного шифрования на общем секретном ключе. 5. Проверить работоспособность приложений: сгенерировать пару «открытый-закрытый ключ»; передать открытый ключ клиентскому приложению; сгенерировать симметричные ключи шифрования (генерация производится на клиентской стороне; ключи генерируются для использования в симметричных шифрах, указанных в варианте задания); передать серверу симметричные ключи, зашифрованные с помощью открытого ключа по алгоритму RSA; на серверной стороне – расшифровать симметричные ключи, после чего зашифровать произвольное сообщение; передать зашифрованные данные клиенту; на клиентской стороне – расшифровать полученные данные. Если открытые и расшифрованные данные совпадают, значит, криптографические функции в приложениях реализованы правильно. все 2. Выполнение В ходе выполнения лабораторной работы разработано программное обеспечение, демонстрирующее работу алгоритмов шифрования RSA и AES. Исходный текст разработанного программного обеспечения на языке Java выглядит следующим образом: Server.java – Приложение-сервер: import java.awt.*; import java.awt.event.*; import java.security.*; import javax.crypto.*; import java.util.concurrent.TimeUnit; import java.util.Arrays; import java.util.Base64; import java.io.*; import java.net.*; import javax.crypto.spec.SecretKeySpec; public class Server extends Panel { String path; Label L1,L2,L3; Button B1,B2; TextField T1; SecretKey secretKey; KeyPair keyPair; public Server(){ try{ path = new File(Server.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getPath(); }catch(URISyntaxException e){System.out.println(e.getMessage());} try{ SecureRandom secureRandom = new SecureRandom(); KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048, secureRandom); keyPair = keyPairGenerator.generateKeyPair(); }catch(Exception e){System.out.println(e.getMessage());} setLayout(new BorderLayout()); Panel p1 = new Panel(); this.add(p1,BorderLayout.CENTER); L1 = new Label("Введите сообщение и нажмите \"Enter\" для отправки:"); p1.add(L1); T1 = new TextField(70); p1.add(T1); L2 = new Label(" "); p1.add(L2); T1.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ String message = e.getActionCommand(); T1.setText(""); try{ cipherWrite(message, path + "/data.txt", secretKey); L2.setText("Отправлено"); try{TimeUnit.SECONDS.sleep(2);}catch(InterruptedException re){System.out.println(re.getMessage());} L2.setText(""); }catch(Exception ex){ L3.setText("Исключение: " + ex.getMessage()); System.out.println(ex.getMessage()); try{TimeUnit.SECONDS.sleep(2);}catch(InterruptedException re){System.out.println(re.getMessage());} L3.setText("Получите симметричный ключ"); } } }); B1 = new Button("Отправить открытый ключ"); B1.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ae){ try{ sendPublicKey(path + "/key.txt", keyPair.getPublic()); L2.setText("Отправлено"); L3.setText("Открытый ключ: " + keyPair.getPublic()); try{TimeUnit.SECONDS.sleep(2);}catch(InterruptedException re){System.out.println(re.getMessage());} L2.setText(""); L3.setText(""); }catch(Exception ex){L3.setText("Исключение: " + ex.getMessage()); System.out.println(ex.getMessage());} } }); p1.add(B1); B2 = new Button("Получить симметричный ключ"); B2.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ae){ try{ byte[] encodedKey = readKey(path + "/symKey.txt", keyPair.getPrivate()); byte[] decodedKey = Base64.getDecoder().decode(Base64.getEncoder().encodeToString(encodedKey)); secretKey = new SecretKeySpec(decodedKey, "AES"); L3.setText("Симметричный ключ: " + secretKey); }catch(Exception ex){ L3.setText("Исключение: " + ex.getMessage()); System.out.println(ex.getMessage()); try{TimeUnit.SECONDS.sleep(2);} catch(InterruptedException re){System.out.println(re.getMessage());} L3.setText("Симметричный ключ не был отправлен"); } } }); p1.add(B2); L3 = new Label(""); this.add(L3,BorderLayout.SOUTH); } public void sendPublicKey(String path, PublicKey publicKey) FileNotFoundException, IOException{ FileOutputStream writer = new FileOutputStream(path); writer.write(publicKey.getEncoded()); writer.flush(); writer.close(); throws } public byte[] readKey(String path, PrivateKey privateKey) throws Exception{ byte[] buf = new byte[128]; int c; FileInputStream reader = new FileInputStream(path); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); CipherInputStream readerCipher = new CipherInputStream(reader, cipher); while((c = readerCipher.read(buf))>0){ if(c < 128) buf = Arrays.copyOf(buf, c); } return buf; } public void cipherWrite(String message, String path, SecretKey secretKey) throws Exception{ byte[] b = message.getBytes(); FileOutputStream writer = new FileOutputStream(path); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); CipherOutputStream writerCipher = new CipherOutputStream(writer, cipher); writerCipher.write(b); writerCipher.flush(); writerCipher.close(); } public static void main(String args[]){ Server panel = new Server(); Frame frame = new Frame("Server"); frame.add(panel); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); frame.setSize((int)screenSize.getWidth()/2-20, (int)screenSize.getHeight()/4); frame.setLocation(10, 10); frame.setVisible(true); frame.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); } } Client.java – Приложение-клиент: import java.awt.*; import java.awt.event.*; import java.security.*; import javax.crypto.*; import java.util.concurrent.TimeUnit; import java.util.Arrays; import java.util.Base64; import java.io.*; import java.net.*; import java.security.spec.X509EncodedKeySpec; public class Client extends Panel { String path, oldLastLine = ""; Label L1,L2; Button B1,B2,B3; SecretKey secretKey; PublicKey public_key; public Client(){ try{ path = new File(Client.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getPath(); }catch(URISyntaxException ex){System.out.println(ex.getMessage());} setLayout(new BorderLayout()); Panel p1 = new Panel(); this.add(p1,BorderLayout.CENTER); L1 = new Label(" "); p1.add(L1); B1 = new Button("Получить открытый ключ"); B1.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ae){ try{ KeyFactory factory = KeyFactory.getInstance("RSA"); public_key = factory.generatePublic(new X509EncodedKeySpec(readKey(path + "/key.txt"))); L2.setText("Открытый ключ: " + public_key); try{TimeUnit.SECONDS.sleep(2);}catch(InterruptedException re){System.out.println(re.getMessage());} L2.setText(""); }catch(Exception ex){ L2.setText("Исключение: " + ex.getMessage()); System.out.println(ex.getMessage()); try{TimeUnit.SECONDS.sleep(2);}catch(InterruptedException re){System.out.println(re.getMessage());} L2.setText("Открытый ключ не был отправлен"); } } }); p1.add(B1); B2 = new Button("Отправить симметричный ключ"); B2.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ae){ try{ KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); secretKey = keyGenerator.generateKey(); sendKey(secretKey, path + "/symKey.txt", public_key); L2.setText("Симметричный ключ: " + secretKey); L1.setText("Отправлено"); try{TimeUnit.SECONDS.sleep(2);}catch(InterruptedException re){System.out.println(re.getMessage());} L1.setText(""); }catch(Exception ex){ L2.setText("Исключение: " + ex.getMessage()); System.out.println(ex.getMessage()); try{TimeUnit.SECONDS.sleep(2);}catch(InterruptedException re){System.out.println(re.getMessage());} L2.setText("Получите открытый ключ"); } } }); p1.add(B2); B3 = new Button("Проверить почту"); B3.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ae){ try{ L2.setText("Сообщение: " + readCipher(path + "/data.txt", secretKey)); }catch(Exception ex){ L2.setText("Нет новых сообщений"); System.out.println(ex.getMessage()); try{TimeUnit.SECONDS.sleep(2);}catch(InterruptedException re){System.out.println(re.getMessage());} L2.setText(""); } } }); p1.add(B3); L2 = new Label(""); this.add(L2,BorderLayout.SOUTH); } public void sendKey(Key key, String path, PublicKey public_key) throws Exception{ FileOutputStream writer = new FileOutputStream(path); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, public_key); CipherOutputStream writerCipher = new CipherOutputStream(writer, cipher); writerCipher.write(key.getEncoded()); writerCipher.flush(); writerCipher.close(); } public String readCipher(String path, Key key) throws Exception{ String lastLine = "Нет новых сообщений"; FileInputStream reader = new FileInputStream(path); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, key); CipherInputStream readerCipher = new CipherInputStream(reader, cipher); byte[] buf = new byte[256]; int c; while((c = readerCipher.read(buf))>0){ if(c < 256) buf = Arrays.copyOf(buf, c); lastLine = new String(buf); if(lastLine.equals(oldLastLine)){ lastLine = "Нет новых сообщений"; throw new Exception(); } else oldLastLine = lastLine; } return lastLine; } public byte[] readKey(String path) throws Exception{ byte[] buf = new byte[2048]; int c; FileInputStream reader = new FileInputStream(path); while((c = reader.read(buf))>0){ if(c < 2048) buf = Arrays.copyOf(buf, c); } return buf; } public static void main(String args[]){ Client panel = new Client(); Frame frame = new Frame("Client"); frame.add(panel); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); frame.setSize((int)screenSize.getWidth()/2-20, (int)screenSize.getHeight()/4); frame.setLocation((int)screenSize.getWidth()/2+10, 10); frame.setVisible(true); frame.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); } } Результат тестирования разработанного программного обеспечения: Вывод В результате выполнения данной лабораторной работы можно сделать вывод о том, что алгоритмы шифрования AES и RSA могут быть реализованы с помощью языка программирования Java.