我在Java Android中实现Hill密码算法时遇到了一些问题。它在某些条件下运行良好但在其他条件下缺乏。
这是正在运行的应用程序。
1。它适用于以下条件
2。对于以下条件,它会带来意想不到的结果
我只是想知道问题来自否定结果。我使用行列式和乘法反转来找到矩阵求逆器。
这是我项目的代码。
MainActivity.java
package com.andri.hilltest;
import java.util.Arrays;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener {
EditText txtPlain, txtKey, txtCipher, txtDecrypt;
Button btnEncrypt, btnCheck, btnDecrypt;
String char_db = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ?!.,";
//String char_db = "ABCDEFGHIJKLMNOPQRSTUVWXYZabc";
int[] array_angka, array_angka2;
int[] array_angka_cipher, array_angka_decrypted;
int[][] M_key = new int[2][2];
int[][] M_inverse = new int [2][2];
int i;
String key_input, ciphertext, plaintext;
int db_length = char_db.length();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtPlain = (EditText) findViewById(R.id.txtPlain);
txtKey = (EditText) findViewById(R.id.txtKey);
txtCipher = (EditText) findViewById(R.id.txtCipher);
txtDecrypt = (EditText) findViewById(R.id.txtDecrypt);
btnEncrypt = (Button) findViewById(R.id.btnEncrypt);
btnDecrypt = (Button) findViewById(R.id.btnDecrypt);
btnCheck = (Button) findViewById(R.id.btnCheck);
btnEncrypt.setOnClickListener(this);
btnCheck.setOnClickListener(this);
btnDecrypt.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v == btnEncrypt){
String plainTextInput = txtPlain.getText().toString();
char[] array_huruf = plainTextInput.toCharArray();
if(array_huruf.length%2!=0)
array_angka = new int[array_huruf.length+1];
else
array_angka = new int[array_huruf.length];
for (i=0 ; i < array_huruf.length ; i++){
int posisi_huruf = char_db.indexOf(array_huruf[i]);
//Toast.makeText(this, "Tombol ditekan " + posisi_huruf , Toast.LENGTH_SHORT).show();
array_angka[i] = posisi_huruf; //if I disable this line the code should run well
}
//jika panjang array ganjil letakkan spasi diakhir array
if(array_huruf.length % 2 != 0 ){
array_angka[array_huruf.length] = 62;
}
array_angka_cipher = new int[array_angka.length];
array_angka_cipher = encrypt_hill(M_key, array_angka);
ciphertext = to_char(array_angka_cipher);
txtCipher.setText(Arrays.toString(array_angka) +"\n\n" + Arrays.toString(array_angka_cipher) + "\n\n" + to_char(array_angka_cipher) );
}
else if (v == btnCheck){
key_input = txtKey.getText().toString();
if (key_input.length() < 4)
Toast.makeText(this, "panjang kunci harus 4 karakter!" , Toast.LENGTH_SHORT).show();
else{
check_kunci(key_input);
}
}
else if(v == btnDecrypt){
char[] array_cipher = ciphertext.toCharArray();
array_angka2 = new int[array_cipher.length];
for (i=0 ; i < array_cipher.length ; i++){
int posisi_huruf = char_db.indexOf(array_cipher[i]);
array_angka2[i] = posisi_huruf;
}
array_angka_decrypted = new int[array_cipher.length];
array_angka_decrypted = decrypt_hill(M_inverse, array_angka2);
plaintext = to_char(array_angka_decrypted);
txtDecrypt.setText(Arrays.toString(array_angka2) + "\n\n" + Arrays.toString(array_angka_decrypted) + "\n\n" + plaintext);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void check_kunci(String kunci){
Toast.makeText(this, kunci , Toast.LENGTH_SHORT).show();
char[] array_kunci = kunci.toCharArray();
int j = 0;
while ( j < array_kunci.length){
//masukkan masing-masing nilai ke matriks kunci
for (int x=0; x < 2; x++){
for (int y=0; y<2; y++){
M_key[x][y] = char_db.indexOf(array_kunci[j]);
j = j+1;
}
}
}
Toast.makeText(this, "hello " + M_key[0][0] + " " + M_key[0][1] + " " + M_key[1][0] + " " + M_key[1][1] , Toast.LENGTH_SHORT).show();
int det = determinant(M_key);
Toast.makeText(this, " determinant = " + det , Toast.LENGTH_SHORT).show();
if (det == 0){
Toast.makeText(this, "Kunci invalid karena determinant = 0" , Toast.LENGTH_SHORT).show();
} else if (det%67==0){
Toast.makeText(this, "Kunci invalid karena determinan memiliki persamaan faktor dgn 67" , Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Kunci Valid, multiplication inverse " + mi(det) , Toast.LENGTH_SHORT).show();
M_inverse = getInverse(M_key, mi(det));
Toast.makeText(this, "Inverse berhasil" + M_inverse[0][0] + " " + M_inverse[0][1] + " " + M_inverse[1][0] + " " + M_inverse[1][1] , Toast.LENGTH_SHORT).show();
String tampil_banding = M_key[0][0] + " " + M_key[0][1] + " " + M_key[1][0] + " " + M_key[1][1] +"\n\n" + M_inverse[0][0] + " " + M_inverse[0][1] + " " + M_inverse[1][0] + " " + M_inverse[1][1];
txtCipher.setText(tampil_banding);
}
}
public int[] encrypt_hill(int[][] key, int[] p){
int str_length;
str_length = txtPlain.length();
if(str_length%2!=0)
str_length = str_length+1;
int[] c = new int[str_length];
int i = 0;
int zz = 0;
for (int b=0; b< str_length/2 ; b++){
for(int j=0; j<2; j++){
for(int x=0; x<2 ; x++){
c[i] += key[j][x]*p[x+zz];
}
i++;
}
zz += 2;
}
return c;
}
private String to_char(int[] num_cipher){
int[] mod_result = new int[num_cipher.length];
char[] parse_cipher = new char[num_cipher.length];
for(int i=0;i<num_cipher.length;i++){
mod_result[i] = Math.abs(num_cipher[i]%67);
parse_cipher[i] = char_db.charAt(mod_result[i]);
}
String cipher_result = new String(parse_cipher);
return cipher_result;
}
public int determinant(int[][] A){
int res;
res = A[0][0]*A[1][1] - A[1][0]*A[0][1];
return res;
}
public int[][] getInverse(int key[][], int mi){
int[][] key_inv = new int[2][2];
key_inv[0][0] = ((key[1][1]*mi)%67);
key_inv[0][1] = (((-1*key[0][1])*mi)%67);
key_inv[1][0] = (((-1*key[1][0])*mi)%67);
key_inv[1][1] = ((key[0][0]*mi)%67);
return key_inv;
}
public int mi(int d)
{
int q,r1,r2,r,t1,t2,t;
r1=67;
r2=d;
t1=0;
t2=1;
while(r1!=1&&r2!=0)
{
q=r1/r2;
r=r1%r2;
t=t1-(t2*q);
r1=r2;
r2=r;
t1=t2;
t2=t;
}
return (t1+t2);
}
public int[] decrypt_hill(int[][] key_invers, int[] p){
int str_length;
str_length = txtPlain.length();
if(str_length%2!=0)
str_length = str_length+1;
int[] c = new int[str_length];
int i = 0;
int zz = 0;
for (int b=0; b< str_length/2 ; b++){
for(int j=0; j<2; j++){
for(int x=0; x<2 ; x++){
c[i] += key_invers[j][x]*p[x+zz];
}
i++;
}
zz += 2;
}
return c;
}
现在我怀疑这个问题来自行列式,mi(乘法逆)和getInverse函数。我真的希望有人可以帮助我找出我的代码或算法有什么问题。
毕竟,我非常感谢您的关注和意图来帮助我。非常感谢你们。对不起,如果我的代码有点混乱,因为我仍然是这方面的初学者。
答案 0 :(得分:0)
来自wikipage http://en.wikipedia.org/wiki/Hill_cipher
并非所有矩阵都具有逆矩阵(参见可逆矩阵)。当且仅当其行列式不为零时,矩阵将具有逆,并且与模块基不具有任何共同因子。因此,如果我们如上所述以模26运算,则行列式必须非零,并且不能被2或13整除。如果行列式为0,或者与模块基数有共同因子,则矩阵不能在Hill中使用密码,必须选择另一个矩阵(否则将无法解密)。幸运的是,满足Hill密码使用条件的矩阵相当普遍。
“abay”不是山密码的有效密钥。
因为没有仔细阅读你的代码而烦恼。
尝试更改
mod_result[i] = Math.abs(num_cipher[i]%67);
到
mod_result[i] = (((num_cipher[i]%67) + 67)%67);
或
mod_result[i] = num_cipher[i]%67;
if(mod_result[i] <0){
mod_result[i] += 67;
}