· 7 years ago · Mar 11, 2018, 10:30 PM
1import org.bouncycastle.jce.provider.BouncyCastleProvider; // provajderot e smesten vo '.jre' fajlot
2import sun.misc.BASE64Decoder;
3import sun.misc.BASE64Encoder;
4import javax.crypto.*;
5import javax.crypto.spec.IvParameterSpec;
6import java.io.IOException;
7import java.security.*;
8
9// klasa za ramkata (se sostoi od zaglavje (header) kako i samata poraka (payload) koja se isprakja)
10class Frame {
11 String header;
12 String payload;
13
14 public Frame(String header, String payload) {
15 this.header = header;
16 this.payload = payload;
17 }
18
19 //potreben metod pri enkripcijata (zaedno so kalkulacijata na MAC-ot) koj gi vrakja bajtite od koi se sostoi ramkata
20 public byte[] getBytes() {
21 String message = header + payload;
22 return message.getBytes();
23 }
24
25 @Override
26 public String toString() {
27 return this.header + '|' + this.payload;
28 }
29}
30
31class CCM {
32 private static String TRANSFORMATION;
33 private SecretKey key;
34 private IvParameterSpec IV;
35 private int headerLength; // dolzhinata na zaglavjeto vo bajti
36
37 public CCM() throws NoSuchAlgorithmException {
38 Security.addProvider(new BouncyCastleProvider()); // dodavanje na provajderot vo ramki na Security API-to
39 TRANSFORMATION = "AES/CCM/NoPadding"; // vo TRANSFORMATION se chuva algoritmot (standardot) zaedno so modot koj kje se koristi vo formata specificirana od JCA (algorithm/mode/padding)
40 key = generateKey(); // generiranje na kluch
41 IV = generateIV(); // generiranje na initialization vector
42 }
43
44 public String encrypt(Frame frame) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchProviderException, BadPaddingException, IllegalBlockSizeException, IOException {
45 Cipher cipher = Cipher.getInstance(TRANSFORMATION, "BC"); // kreiranje na shifruvach soglasno so navedenata transformacija i provajder ('BC')
46 cipher.init(Cipher.ENCRYPT_MODE, key, IV); // naveduvanje na modot (enkripcija / dekripcija) vo koj kje raboti zaedno so kluchot i IV-ot
47 byte[] encryptedPayload = cipher.doFinal(frame.getBytes()); // so doFinal metodot se izvrshuva enkripcijata / dekripcijata i sodrzhinata se smestuva vo nizata 'encryptedPayload'.
48 // Pritoa vo poslednite 8 bajti od nizata se naogja MAC-ot
49 byte[] headerBytes = frame.header.getBytes();
50 headerLength = headerBytes.length;
51 byte[] encryptedFrame = new byte[headerLength + encryptedPayload.length];
52 // vo sledniot for ciklus se vrshi konkatenacija na zaglavjeto so enkriptiranata sodrzhina
53 for(int i = 0; i < encryptedFrame.length; i++) {
54 if(i < headerLength) {
55 encryptedFrame[i] = headerBytes[i];
56 }
57 else{
58 encryptedFrame[i] = encryptedPayload[i - headerLength];
59 }
60 }
61
62 return new BASE64Encoder().encode(encryptedFrame);
63 }
64
65 public Frame decrypt(String frame) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, IOException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
66 Cipher cipher = Cipher.getInstance(TRANSFORMATION, "BC");
67 cipher.init(Cipher.DECRYPT_MODE, key, IV); // edinstveno go promenuvame modot (dekripcija)
68 byte[] encryptedFrame = new BASE64Decoder().decodeBuffer(frame); // bidejkji na vlez primame enkriptirana ramka enkodirana so base-64 format, pravime nejzino dekodiranje
69 byte[] headerBytes = new byte[headerLength];
70 byte[] encryptedPayload = new byte[encryptedFrame.length - headerLength];
71 // ja izminuvame ramkata bajt po bajt i koristejkji ja dolzhinata na zaglavjeto, gi odvojuvame bajtite na zaglavjeto vo headerBytes (koi ne se enkriptirani). Ostatokot (enkriptiranata sodrzhina) se smestuva vo encryptedPayload
72 for(int i = 0; i < encryptedFrame.length; i++) {
73 if(i < headerLength) {
74 headerBytes[i] = encryptedFrame[i];
75 }
76 else {
77 encryptedPayload[i - headerLength] = encryptedFrame[i];
78 }
79 }
80
81 byte[] decryptedPayload = cipher.doFinal(encryptedPayload); // dekripcija na sodrzhinata
82 return new Frame(new String(headerBytes), new String(decryptedPayload).substring(headerLength));
83 }
84
85 private SecretKey generateKey() throws NoSuchAlgorithmException {
86 KeyGenerator keygen = KeyGenerator.getInstance("AES");
87 keygen.init(128); // se kreira generator za soodvetniot algoritam so navedenata golemina na kluchot vo bitovi (vo sluchajov 128)
88 return keygen.generateKey(); // ni vrakja nekoj sluchajno generiran kluch
89 }
90
91 private IvParameterSpec generateIV() {
92 SecureRandom random = new SecureRandom(); // pomoshna klasa za generiranje na sluchaen IV
93 byte[] iv = new byte[7];
94 random.nextBytes(iv); // generira sluchaen IV so golemina od 7 do 13 bajti (nie odreduvame kolku; vlijae vrz maksimalnata dolzhina na ramkite) i go smestuva vo 'iv'
95 return new IvParameterSpec(iv); // IvParameterSpec sluzhi kako wrapper na IV-ot so edinstven metod getIV()
96 }
97}
98
99public class Main {
100 public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchProviderException, BadPaddingException, IllegalBlockSizeException, IOException {
101 CCM ccm = new CCM();
102 Frame frame = new Frame("zaglavje", "poraka za prakjanje");
103 String encryptedFrame = ccm.encrypt(frame);
104 System.out.println("Encrypted frame (using base64 encoding scheme): " + encryptedFrame);
105 System.out.println("Decrypted frame: " + ccm.decrypt(encryptedFrame));
106 }
107}