【问题标题】:Problems with the key encryption / decryption AES (Rijndael)密钥加密/解密 AES (Rijndael) 的问题
【发布时间】:2012-07-20 05:49:31
【问题描述】:

我正在开发一个使用 AES 算法 (Rijndael) 加密和解密传输信息的 Android 项目。

我使用的 WS 有一个用于加密和解密的固定密钥。所以我必须在源代码中有相同的键。

但是,此密钥经过处理后可用于加密/解密。问题是关键是没有经过适当的治疗。原因:特殊字符。我尝试使用其他没有特殊字符的键,效果很好。

下面是算法的摘录:

final String KEY_GENERATION_ALG = "d(*Mu96p@lg91¨%0c*f7&d^`pkçly$f7";
    final int HASH_ITERATIONS = 10000;
    final int KEY_LENGTH = 256;

    char[] humanPassphrase = { 'P', 'e', 'r', ' ', 'v', 'a', 'l', 'l', 'u',
            'm', ' ', 'd', 'u', 'c', 'e', 's', ' ', 'L', 'a', 'b', 'a',
            'n', 't' };
    byte[] salt = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE,
            0xF }; 

    PBEKeySpec myKeyspec = new PBEKeySpec(humanPassphrase, salt, HASH_ITERATIONS, KEY_LENGTH);
    SecretKeyFactory keyfactory = null;
    SecretKey sk = null;
    SecretKeySpec skforAES = null;

    try {
        keyfactory = SecretKeyFactory.getInstance(KEY_GENERATION_ALG);
        sk = keyfactory.generateSecret(myKeyspec);

    } catch (NoSuchAlgorithmException nsae) {
        Log.e("AESdemo",
                "no key factory support for PBEWITHSHAANDTWOFISH-CBC");

    } catch (InvalidKeySpecException ikse) {
        Log.e("AESdemo", "invalid key spec for PBEWITHSHAANDTWOFISH-CBC");

    }

    byte[] skAsByteArray = sk.getEncoded();
    skforAES = new SecretKeySpec(skAsByteArray, "AES");

    final String CIPHERMODEPADDING = "AES/CBC/PKCS7Padding";

    byte[] iv = { 0xA, 1, 0xB, 5, 4, 0xF, 7, 9, 0x17, 3, 1, 6, 8, 0xC, 0xD,
            91 };
    IvParameterSpec IV = new IvParameterSpec(iv);

    String decrypted = new String(decrypt(CIPHERMODEPADDING, skforAES, IV, ciphertext));

    return decrypted;

这是关键:d(*Mu96p@lg91¨%0c*f7&d^`pkçly$f7

应用程序在 catch 块“NoSuchAlgorithmException”上崩溃。

有人经历过吗?我不知道如何解决这个问题。

非常感谢!


还是没用,马库斯。 :/

错误是这样的:

“无效的密钥异常。”

看看我的代码怎么样。

public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    String desc = "starting work...";
    TextView tv1 = (TextView) findViewById(R.id.tv1);
    tv1.setText(desc);

    byte[] KEY_GENERATION_ALG = null;
    try {
        KEY_GENERATION_ALG = ("teste").getBytes("ISO-8859-1");
    } catch (UnsupportedEncodingException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    final int HASH_ITERATIONS = 10000;
    final int KEY_LENGTH= 256;
    SecretKeySpec skforAES=null;
    // Obviously, you must not embed the human-friendly passphrase in your code, as I have done here.
    // The passphrase should be kept outside the mobile device, and the user prompted to enter it.
    // It is supplied as a literal here for convenience of this demonstration
    /*char [] humanPassphrase = {'P','e','r',' ','v','a','l','l','u','m',' ',
                               'd','u','c','e','s',' ','L','a','b','a','n','t' };
    byte [] salt = {0,1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF};  // must save this for next time we want the key


    PBEKeySpec myKeyspec = new PBEKeySpec(humanPassphrase, salt, HASH_ITERATIONS, KEY_LENGTH);
    tv1.setText("PBEKeySpec generated");
    SecretKeyFactory keyfactory=null;
    SecretKey sk=null;
    SecretKeySpec skforAES=null;
    try {
        keyfactory = SecretKeyFactory.getInstance(KEY_GENERATION_ALG);
        sk = keyfactory.generateSecret(myKeyspec);

    } catch (NoSuchAlgorithmException nsae) {
        Log.e("AESdemo", "no key factory support for PBEWITHSHAANDTWOFISH-CBC" );
    } catch (InvalidKeySpecException ikse) {
        Log.e("AESdemo", "invalid key spec for PBEWITHSHAANDTWOFISH-CBC" );
    }

    // This is our secret key.  We could just save this to a file instead of regenerating it
    // each time it is needed.  But that file cannot be on the device (too insecure).  It could
    // be secure if we kept it on a server accessible through https.
    byte[] skAsByteArray = sk.getEncoded();*/
    try {
        skforAES = new SecretKeySpec(KEY_GENERATION_ALG, "AES");
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    final String CIPHERMODEPADDING = "AES/CBC/PKCS7Padding";

    // must save the IV for use when we want to decrypt the text
    byte [] iv = {0xA,1,0xB,5,4,0xF,7,9,0x17,3,1,6,8,0xC,0xD,91};   
    IvParameterSpec IV = new IvParameterSpec(iv);
    byte[] plaintext=null;
    try {
        // Obviously in a real use scenario, the plaintext will not be a literal in your app.
        // This plaintext comes from chapter X of "Alice's Adventures in Wonderland" by Lewis Carroll
        // I like the emphasis the author places on clear explanations ...
        plaintext = (
                  "Tis the voice of the Lobster; I heard him declare,\n"
                + "    \"You have baked me too brown, I must sugar my hair.\"\n "
                + "    As a duck with its eyelids, so he with his nose\n"
                + "    Trims his belt and his buttons, and turns out his toes.'\n"
                + "`I should like to have it explained,' said the Mock Turtle.\n"
                + "`She can't explain it,' said the Gryphon hastily. `Go on with the next verse.'\n"
                + "Alice did not dare to disobey, though she felt sure it would all come wrong, "
                + "and she went on in a trembling voice:-- \n"
                + "    `I passed by his garden, and marked, with one eye, \n"
                + "     How the Owl and the Panther were sharing a pie--' \n"
                + "`What is the use of repeating all that stuff,' the Mock Turtle interrupted, "
                + "`if you don't explain it as you go on? It's by far the most confusing thing I ever heard!'"
                ).getBytes("ISO-8859-1");
    } catch (UnsupportedEncodingException uee) {
        Log.e("AESdemo", "no String support for ISO-8859-1" );
    }

    Log.i("AESdemo", "plaintext length =" + plaintext.length );


    byte[] ciphertext = encrypt(CIPHERMODEPADDING, skforAES, IV, plaintext);

    String decrypted = new String( decrypt(CIPHERMODEPADDING, skforAES, IV, ciphertext) );

    tv1.setText(decrypted);
}

//  Use this method if you want to add the padding manually
//  AES deals with messages in blocks of 16 bytes.
//  This method looks at the length of the message, and adds bytes at the end
//  so that the entire message is a multiple of 16 bytes.
//  the padding is a series of bytes, each set to the total bytes added (a number in range 1..16).
byte [] addPadding (byte[] plain) {
    byte plainpad[] = null;
    int shortage  = 16 - (plain.length % 16);
    // if already an exact multiple of 16, need to add another block of 16 bytes
    if (shortage==0) shortage=16;

    // reallocate array bigger to be exact multiple, adding shortage bits.
    plainpad = new byte[ plain.length+shortage ];
    for (int i=0;i< plain.length; i++) {
        plainpad[i]=plain[i];
    }
    for (int i=plain.length;i<plain.length+shortage;i++) {
        plainpad[i]=(byte)shortage;
    }
    return plainpad;
}

//  Use this method if you want to remove the padding manually
// This method removes the padding bytes
byte [] dropPadding (byte[] plainpad) {
    byte plain[] = null;
    int drop  = plainpad[plainpad.length-1];  //last byte gives number of bytes to drop

    // reallocate array smaller, dropping the pad bytes.
    plain = new byte[ plainpad.length - drop ];
    for (int i=0;i< plain.length; i++) {
        plain[i]=plainpad[i];
        plainpad[i]=0;  // don't keep a copy of the decrypt
    }
    return plain;
}


byte [] encrypt(String cmp, SecretKey sk, IvParameterSpec IV, byte[] msg) {
    try {
        Cipher c = Cipher.getInstance(cmp);
        c.init(Cipher.ENCRYPT_MODE, sk, IV);
        return c.doFinal(msg);
    } catch (NoSuchAlgorithmException nsae) {
        Log.e("AESdemo", "no cipher getinstance support for "+cmp );
    } catch (NoSuchPaddingException nspe) {
        Log.e("AESdemo", "no cipher getinstance support for padding " + cmp );
    } catch (InvalidKeyException e) {
        Log.e("AESdemo", "invalid key exception" );
    } catch (InvalidAlgorithmParameterException e) {
        Log.e("AESdemo", "invalid algorithm parameter exception" );
    } catch (IllegalBlockSizeException e) {
        Log.e("AESdemo", "illegal block size exception" );
    } catch (BadPaddingException e) {
        Log.e("AESdemo", "bad padding exception" );
    }
    return null;
}

byte [] decrypt(String cmp, SecretKey sk, IvParameterSpec IV, byte[] ciphertext) {
    try {
        Cipher c = Cipher.getInstance(cmp);
        c.init(Cipher.DECRYPT_MODE, sk, IV);
        return c.doFinal(ciphertext);
    } catch (NoSuchAlgorithmException nsae) {
        Log.e("AESdemo", "no cipher getinstance support for "+cmp );
    } catch (NoSuchPaddingException nspe) {
        Log.e("AESdemo", "no cipher getinstance support for padding " + cmp );
    } catch (InvalidKeyException e) {
        Log.e("AESdemo", "invalid key exception" );
    } catch (InvalidAlgorithmParameterException e) {
        Log.e("AESdemo", "invalid algorithm parameter exception" );
    } catch (IllegalBlockSizeException e) {
        Log.e("AESdemo", "illegal block size exception" );
    } catch (BadPaddingException e) {
        Log.e("AESdemo", "bad padding exception" );
    }
    return null;
}

}

【问题讨论】:

    标签: android key aes rijndael


    【解决方案1】:

    我并没有真正关注您在此处所做的事情,但您似乎没有正确使用 API。 SecretKeyFactory.getInstance() 的参数应该是密钥算法的名称,而不是实际密钥。由于您已经拥有密钥,因此您不需要使用 SecretKeyFactory 为您生成密钥。

    尝试使用您的密钥直接创建 SecretKeySpec 实例,如下所示:

    skforAES = new SecretKeySpec(KEY.getBytes("utf-8"), "AES");
    

    【讨论】:

    • 首先感谢您的关注!尽管您所说的很有意义,但仍会继续中断。但现在错误是“无效的密钥异常”。但我绝对确定密钥是正确的。我可以尝试什么?
    • Marcus,帮你,这里是WS的加密代码:stackoverflow.com/questions/11564719/…
    • 不确定您的密钥是哪种编码 - 您可能不应该将其存储为字符串,而应存储为字节数组。试试我更新的答案,看看效果是否更好。
    • 嗨,马库斯。我按照您的指示做了,但仍然没有工作。我发布了我的代码的更新。那是对的吗?谢谢!
    • 嗨,马库斯,你好吗?我要感谢您的指示。一切正常。问题是我后来发现的,是在 IV 上。但是现在一切都解决了!谢谢!
    猜你喜欢
    • 2016-05-26
    • 1970-01-01
    • 1970-01-01
    • 2013-08-24
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多