Міністерство освіти і науки
Національний університет „Львівська політехніка”
Кафедра ЕОМ
Лабораторна робота №2
з дисципліни:
“Проектування засобів захисту інформації в комп'ютерних системах та мережах”
на тему:
“Формування цифрового підпису згідно стандарту DSS”
Львів 2017
Мета: Реалізувати програму формування цифрового підпису вхідного повідомлення згідно стандарту DSS.
Теоретичні відомості
Вимоги до цифрового підпису
Аутентифікація захищає двох учасників, які обмінюються повідомленнями від
втручання деякої третьої сторони. Зазвичай проста аутентифікація не захищає
учасників один від одного, оскільки між самими учасниками можуть виникати
певного роду спори.
Наприклад, припустимо, що Роман посилає Андрію аутентифіковане
повідомлення, аутентифікація здійснюється на основі спільного секретного ключа.
Розглянемо можливі непорозуміння, які можуть при цьому виникати:
1. Андрій може підробити повідомлення і стверджувати, що воно прийшло від
Романа. Для цього достатньо просто створити повідомлення і приєднати код
аутентифікації, використовуючи спільний ключ.
2. Роман може відправити повідомлення Андрію, а потім спокійно заперечувати
факт передачі цього повідомлення. Оскільки Андрій може підробити
повідомлення, то він не зможе довести, що Роман дійсно відправляв
повідомлення.
У випадку, коли обидві сторони не довіряють один одному, необхідно дещо
більше, ніж аутентифікація на основі спільного секрету. Можливим вирішенням
подібної проблеми є використання цифрового підпису. Цифровий підпис має
наступні властивості:
1. Забезпечує можливість перевірки автора, дати та часу формування підпису.
2. Забезпечує можливість аутентифікації вмісту повідомлення під час
формування підпису.
3. Підпис перевіряється третьою стороною для розв’язання спорів.
Таким чином, функція цифрового підпису включає функцію аутентифікації. На
основі цих властивостей можна сформулювати наступні вимоги до цифрового
підпису:
1. Підпис повинен бути бітовим об'єктом, що залежить від підписаного
повідомлення.
2. Підпис повинен містити деяку унікальну інформацію відправника для
запобігання підробки або відмови.
3. Алгоритм формування цифрового підпису має бути достатньо простим.
4. Підпис повинен легко перевірятися.
5. Підробка цифрового підпису шляхом створення нового повідомлення для
існуючого цифрового підпису або створення фальшивого цифрового підпису
для деякого повідомлення має бути неможливою.
6. Цифровий підпис повинен бути достатньо компактним і не займати багато
пам’яті.
Для реалізації систем цифрового підпису використовують поєднання сильних
хеш-функцій та асиметричних криптосистем.
Завдання: в ході роботи необхідно засвоїти основні принципи побудови алгоритмів формування цифрових підписів повідомлень, розробити демонстраційну програму формування цифрового підпису вхідного повідомлення згідно стандарту DSS.
Текст програми:
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.nio.ByteBuffer;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
@SuppressWarnings("serial")
public class DSA extends JFrame implements ActionListener {
JButton jButtonCalc = new JButton("Calculate");
JButton jButtonEnter = new JButton("Form");
JButton jButtonClear = new JButton("Reset");
JButton jButtonCheck = new JButton("Verify");
JLabel jLabel1, jLabel2, jLabel3, jLabel4, jLabel5, jLabel6, jLabel7;
JTextArea jTextMessage, jTextOutput, jTextSecretKey;
long q = 0, P = 0, G = 0, k = 0, X = 0, Y = 0, r = 0, s = 0, m = 0, u1 = 0, u2 = 0, v = 0, w = 0;
byte[] mHex;
int j, temp;
int A, B, C, D, E;
int[] H = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 };
int F;
@SuppressWarnings("deprecation")
public DSA() {
super("DSA");
setSize(575, 440);
Container cc = getContentPane();
cc.setBackground(Color.ORANGE);
jLabel2 = new JLabel("Enter button Calculate to calculate parametres");
jLabel2.setForeground(Color.BLACK);
jLabel2.setFont(new Font("Arial", Font.PLAIN, 20));
jLabel2.setBounds(30, 60, 500, 50);
cc.add(jLabel2);
jLabel7 = new JLabel();
jLabel7.setBounds(30, 90, 500, 30);
jLabel7.setFont(new Font("Arail", Font.PLAIN, 20));
cc.add(jLabel7);
jTextSecretKey = new JTextArea(10, 50);
jTextSecretKey.setLineWrap(true);
jTextSecretKey.setBounds(30, 120, 500, 25);
jTextSecretKey.setFont(new Font("Arail", Font.PLAIN, 20));
cc.add(jTextSecretKey);
jLabel5 = new JLabel("Enter messages");
jLabel5.setForeground(Color.BLACK);
jLabel5.setFont(new Font("Arial", Font.PLAIN, 20));
jLabel5.setBounds(30, 135, 500, 50);
cc.add(jLabel5);
jTextMessage = new JTextArea(10, 50);
jTextMessage.setLineWrap(true);
jTextMessage.setBounds(30, 175, 500, 50);
jTextMessage.setFont(new Font("Arial", Font.PLAIN, 20));
cc.add(jTextMessage);
jLabel3 = new JLabel("Signature");
jLabel3.setForeground(Color.BLACK);
jLabel3.setFont(new Font("Arial", Font.PLAIN, 20));
jLabel3.setBounds(30, 215, 200, 50);
cc.add(jLabel3);
jTextOutput = new JTextArea(10, 50);
jTextOutput.setBounds(30, 255, 500, 50);
jTextOutput.setFont(new Font("Arail", Font.PLAIN, 20));
jTextOutput.setEditable(false);
cc.add(jTextOutput);
jButtonCalc.setBounds(30, 310, 100, 30);
cc.add(jButtonCalc);
jButtonEnter.setBounds(140, 310, 100, 30);
cc.add(jButtonEnter);
jButtonCheck.setBounds(250, 310, 100, 30);
cc.add(jButtonCheck);
jButtonClear.setBounds(360, 310, 100, 30);
cc.add(jButtonClear);
jLabel6 = new JLabel();
jLabel6.setForeground(Color.BLACK);
jLabel6.setFont(new Font("Arial", Font.PLAIN, 20));
jLabel6.setBounds(30, 330, 200, 50);
cc.add(jLabel6);
jLabel4 = new JLabel();
cc.add(jLabel4);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jButtonCalc.addActionListener(this);
jButtonEnter.addActionListener(this);
jButtonClear.addActionListener(this);
jButtonCheck.addActionListener(this);
show();
}
public static void main(String[] args) {
new DSA();
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == jButtonCalc) {
calculate();
}
if (e.getSource() == jButtonEnter) {
form();
}
if (e.getSource() == jButtonClear) {
reset();
}
if (e.getSource() == jButtonCheck) {
check();
}
}
public void calculate() {
try {
while (q == 0)
q = (long) (Math.random() * 100);
if (q % 2 == 0)
q--;
P = q * 2 + 1;
G = (long) Math.pow(2, 2);
jLabel7.setText("Enter X (1 < X < " + q + ")");
} catch (Exception ex) {
}
}
public void form() {
try {
String M = jTextMessage.getText();
Digest digester = new Digest();
byte[] dataBuffer = (M).getBytes();
String thedigest = digester.digestIt(dataBuffer);
mHex = hexToBinary(thedigest);
String S = jTextSecretKey.getText();
X = Long.valueOf(S);
Y = ((long) Math.pow((G % P), X)) % P;
while (!(k > 1 && k < q))
k = (long) (Math.random() * 100);
if (k % 2 == 0)
k--;
long temp = degreeMod(G, k, P);
r = temp % q;
long k_1 = searchDiv(k, q);
m = modBig(mHex, q);
long temp1 = r * X;
long temp2 = (temp1 + m) % q;
long temp3 = k_1 % q;
s = (temp2 * temp3) % q;
System.out.println("Parametres:");
System.out.println("q = " + q);
System.out.println("P = " + P);
System.out.println("G = " + G);
System.out.println("X = " + X);
System.out.println("Y = " + Y);
System.out.println("message = " + M);
System.out.println("SHA-1 = " + thedigest);
System.out.println("m = " + m);
System.out.println("k = " + k);
System.out.println("k-1 = " + k_1);
System.out.println("r = " + r);
System.out.println("s = " + s);
System.out.println("-------------------------------------------------------------");
jTextOutput.setText(M + ", " + r + ", " + s);
System.out.println("Signature:");
System.out.println(M + ", " + r + ", " + s);
System.out.println("------------------------------------------------------------");
} catch (Exception ex) {
}
}
public void reset() {
try {
jTextMessage.setText("");
jTextOutput.setText("");
jLabel7.setText("");
jTextSecretKey.setText("");
q = 0;
P = 0;
G = 0;
k = 0;
X = 0;
Y = 0;
r = 0;
s = 0;
m = 0;
u1 = 0;
u2 = 0;
v = 0;
w = 0;
System.out.println("Reset");
System.out.println("-------------------------------------------------------------");
} catch (Exception fnfe) {
}
}
public void check() {
try {
long temp1 = searchDiv(s, q);
w = temp1 % q;
u1 = (m * w) % q;
u2 = (r * w) % q;
long temp2 = degreeMod(G, u1, P);
long temp3 = degreeMod(Y, u2, P);
v = ((temp2 * temp3) % P) % q;
System.out.println("Verify:");
System.out.println("w = " + w);
System.out.println("u1 = " + u1);
System.out.println("u2 = " + u2);
System.out.println("v = " + v);
System.out.println("-------------------------------------------------------------");
if (v == r) {
jLabel6.setText("Signature verified");
System.out.println("Signature verified.");
System.out.println("------------------------------------------------------------");
} else {
jLabel6.setText("Signature not verified");
System.out.println("Signature not verified");
System.out.println("------------------------------------------------------------");
}
} catch (Exception fnfe) {
}
}
public static byte[] decimalToBinary(long d) {
byte[] b = new byte[64];
int i = 0;
while (d != 0) {
b[i] = (byte) (d % 2);
d = d / 2;
i++;
}
return b;
}
public static long binaryToDecimal(byte[] b) {
long n = 0;
for (int i = 0; i < b.length; i++)
n += b[i] * Math.pow(2, i);
return n;
}
public static long searchDiv(long n, long mod) {
int i = 0;
while ((i * n) % mod != 1)
i++;
return i;
}
public static byte[] hexToBinary(String s) {
byte[] b = new byte[160];
String hex = s.toLowerCase();
for (int i = 0, j = hex.length() - 1; j >= 0; i += 4, j--) {
if (hex.charAt(j) == '0') {
b[i] = 0;
b[i + 1] = 0;
b[i + 2] = 0;
b[i + 3] = 0;
}
if (hex.charAt(j) == '1') {
b[i] = 1;
b[i + 1] = 0;
b[i + 2] = 0;
b[i + 3] = 0;
}
if (hex.charAt(j) == '2') {
b[i] = 0;
b[i + 1] = 1;
b[i + 2] = 0;
b[i + 3] = 0;
}
if (hex.charAt(j) == '3') {
b[i] = 1;
b[i + 1] = 1;
b[i + 2] = 0;
b[i + 3] = 0;
}
if (hex.charAt(j) == '4') {
b[i] = 0;
b[i + 1] = 0;
b[i + 2] = 1;
b[i + 3] = 0;
}
if (hex.charAt(j) == '5') {
b[i] = 1;
b[i + 1] = 0;
b[i + 2] = 1;
b[i + 3] = 0;
}
if (hex.charAt(j) == '6') {
b[i] = 0;
b[i + 1] = 1;
b[i + 2] = 1;
b[i + 3] = 0;
}
if (hex.charAt(j) == '7') {
b[i] = 1;
b[i + 1] = 1;
b[i + 2] = 1;
b[i + 3] = 0;
}
if (hex.charAt(j) == '8') {
b[i] = 0;
b[i + 1] = 0;
b[i + 2] = 0;
b[i + 3] = 1;
}
if (hex.charAt(j) == '9') {
b[i] = 1;
b[i + 1] = 0;
b[i + 2] = 0;
b[i + 3] = 1;
}
if (hex.charAt(j) == 'a') {
b[i] = 0;
b[i + 1] = 1;
b[i + 2] = 0;
b[i + 3] = 1;
}
if (hex.charAt(j) == 'b') {
b[i] = 1;
b[i + 1] = 1;
b[i + 2] = 0;
b[i + 3] = 1;
}
if (hex.charAt(j) == 'c') {
b[i] = 0;
b[i + 1] = 0;
b[i + 2] = 1;
b[i + 3] = 1;
}
if (hex.charAt(j) == 'd') {
b[i] = 1;
b[i + 1] = 0;
b[i + 2] = 1;
b[i + 3] = 1;
}
if (hex.charAt(j) == 'e') {
b[i] = 0;
b[i + 1] = 1;
b[i + 2] = 1;
b[i + 3] = 1;
}
if (hex.charAt(j) == 'f') {
b[i] = 1;
b[i + 1] = 1;
b[i + 2] = 1;
b[i + 3] = 1;
}
}
return b;
}
public static long modBig(byte[] arr, long n) {
int pos1 = 0, pos2 = 0, length = 63;
long res = 0;
int i = 63;
byte[] temp1 = new byte[length];
while (i < 160) {
System.arraycopy(arr, pos1, temp1, pos2, length);
long temp2 = binaryToDecimal(temp1);
long temp3 = temp2 % n;
res = temp3;
byte[] temp4 = decimalToBinary(temp3);
pos1 += length;
pos2 = findOne(temp4) + 1;
length = 62 - findOne(temp4);
// temp1 = null;
byte[] temp5 = new byte[64];
System.arraycopy(temp4, 0, temp5, 0, length);
temp1 = temp5;
i += length;
}
return res;
}
public static int findOne(byte[] arr) {
int res = 0;
for (int i = arr.length - 1; i >= 0; i--) {
if (arr[i] == 1) {
res = i;
break;
}
}
return res;
}
public static long degreeMod(long a, long deg, long mod) {
long c = 0, d = 1;
byte[] degree = decimalToBinary(deg);
for (int i = degree.length - 1; i >= 0; i--) {
c = c * 2;
d = (d * d) % mod;
if (degree[i] == 1) {
c = c + 1;
d = (d * a) % mod;
}
}
return d;
}
public class Digest {
String digestIt(byte[] dataIn) {
byte[] paddedData = padTheMessage(dataIn);
int[] H = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 };
int[] K = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
if (paddedData.length % 64 != 0) {
System.out.println("Invalid padded data length.");
System.exit(0);
}
int passesReq = paddedData.length / 64;
byte[] work = new byte[64];
for (int passCntr = 0; passCntr < passesReq; passCntr++) {
System.arraycopy(paddedData, 64 * passCntr, work, 0, 64);
processTheBlock(work, H, K);
}
return intArrayToHexStr(H);
}
private byte[] padTheMessage(byte[] data) {
int origLength = data.length;
int tailLength = origLength % 64;
int padLength = 0;
if ((64 - tailLength >= 9)) {
padLength = 64 - tailLength;
} else {
padLength = 128 - tailLength;
}
byte[] thePad = new byte[padLength];
thePad[0] = (byte) 0x80;
long lengthInBits = origLength * 8;
for (int cnt = 0; cnt < 8; cnt++) {
thePad[thePad.length - 1 - cnt] = (byte) ((lengthInBits >> (8 * cnt)) & 0x00000000000000FF);
}
byte[] output = new byte[origLength + padLength];
System.arraycopy(data, 0, output, 0, origLength);
System.arraycopy(thePad, 0, output, origLength, thePad.length);
return output;
}
private void processTheBlock(byte[] work, int H[], int K[]) {
int[] W = new int[80];
for (int outer = 0; outer < 16; outer++) {
int temp = 0;
for (int inner = 0; inner < 4; inner++) {
temp = (work[outer * 4 + inner] & 0x000000FF) << (24 - inner * 8);
W[outer] = W[outer] | temp;
}
}
for (int j = 16; j < 80; j++) {
W[j] = rotateLeft(W[j - 3] ^ W[j - 8] ^ W[j - 14] ^ W[j - 16], 1);
}
A = H[0];
B = H[1];
C = H[2];
D = H[3];
E = H[4];
for (int j = 0; j < 20; j++) {
F = (B & C) | ((~B) & D);
temp = rotateLeft(A, 5) + F + E + K[0] + W[j];
E = D;
D = C;
C = rotateLeft(B, 30);
B = A;
A = temp;
}
for (int j = 20; j < 40; j++) {
F = B ^ C ^ D;
temp = rotateLeft(A, 5) + F + E + K[1] + W[j];
E = D;
D = C;
C = rotateLeft(B, 30);
B = A;
A = temp;
}
for (int j = 40; j < 60; j++) {
F = (B & C) | (B & D) | (C & D);
temp = rotateLeft(A, 5) + F + E + K[2] + W[j];
E = D;
D = C;
C = rotateLeft(B, 30);
B = A;
A = temp;
}
for (int j = 60; j < 80; j++) {
F = B ^ C ^ D;
temp = rotateLeft(A, 5) + F + E + K[3] + W[j];
E = D;
D = C;
C = rotateLeft(B, 30);
B = A;
A = temp;
}
H[0] += A;
H[1] += B;
H[2] += C;
H[3] += D;
H[4] += E;
}
final int rotateLeft(int value, int bits) {
int q = (value << bits) | (value >>> (32 - bits));
return q;
}
}
private String intArrayToHexStr(int[] data) {
String output = "";
String tempStr = "";
int tempInt = 0;
for (int cnt = 0; cnt < data.length; cnt++) {
tempInt = data[cnt];
tempStr = Integer.toHexString(tempInt);
if (tempStr.length() == 1) {
tempStr = "0000000" + tempStr;
} else if (tempStr.length() == 2) {
tempStr = "000000" + tempStr;
} else if (tempStr.length() == 3) {
tempStr = "00000" + tempStr;
} else if (tempStr.length() == 4) {
tempStr = "0000" + tempStr;
} else if (tempStr.length() == 5) {
tempStr = "000" + tempStr;
} else if