我的山密码有什么问题? (Java Android)

时间:2014-04-20 09:36:41

标签: java android cryptography

我在Java Android中实现Hill密码算法时遇到了一些问题。它在某些条件下运行良好但在其他条件下缺乏。

这是正在运行的应用程序。

1。它适用于以下条件

**Ok for below input**

2。对于以下条件,它会带来意想不到的结果

the problem comes here

我只是想知道问题来自否定结果。我使用行列式和乘法反转来找到矩阵求逆器。

这是我项目的代码。

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函数。我真的希望有人可以帮助我找出我的代码或算法有什么问题。

毕竟,我非常感谢您的关注和意图来帮助我。非常感谢你们。对不起,如果我的代码有点混乱,因为我仍然是这方面的初学者。

1 个答案:

答案 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;
}