Android 密钥加密/解密AES(Rijndael)的问题

Android 密钥加密/解密AES(Rijndael)的问题,android,key,aes,rijndael,Android,Key,Aes,Rijndael,我正在从事一个Android项目,该项目使用AES算法(Rijndael)加密和解密被贩运的信息 WS-I consume具有用于加密和解密的固定密钥。所以我必须在源代码中使用相同的密钥 但是,该密钥经过处理,随后用于加密/解密。问题是,关键在于没有进行适当的治疗。原因:特殊的字符。我尝试使用其他没有特殊字符的键,效果非常好 下面是算法的摘录: final String KEY_GENERATION_ALG = "d(*Mu96p@lg91¨%0c*f7&d^`pkçly$f7";

我正在从事一个Android项目,该项目使用AES算法(Rijndael)加密和解密被贩运的信息

WS-I consume具有用于加密和解密的固定密钥。所以我必须在源代码中使用相同的密钥

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

下面是算法的摘录:

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;
}
公共类MainActivity扩展活动{
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String desc=“开始工作…”;
TextView tv1=(TextView)findViewById(R.id.tv1);
tv1.setText(desc);
字节[]键\u生成\u ALG=null;
试一试{
KEY_GENERATION_ALG=(“teste”).getBytes(“ISO-8859-1”);
}捕获(不支持DencodingException e1){
//TODO自动生成的捕捉块
e1.printStackTrace();
}
最终整数散列_迭代=10000;
最终整数键长度=256;
SecretKeySpec skforAES=null;
//显然,您不能像我在这里所做的那样,在代码中嵌入人性化的密码短语。
//密码短语应保存在移动设备之外,并提示用户输入密码。
//为了便于本演示,此处将其作为文字提供
/*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=新的PBEKeySpec(humanPassphrase、salt、HASH_迭代、密钥长度);
tv1.setText(“生成的PBEKeySpec”);
SecretKeyFactory keyfactory=null;
SecretKey sk=null;
SecretKeySpec skforAES=null;
试一试{
keyfactory=SecretKeyFactory.getInstance(KEY\u GENERATION\u ALG);
sk=keyfactory.GenerateCret(myKeyspec);
}捕获(无算法异常nsae){
Log.e(“AESdemo”,“PBewithsha和Twofish-CBC无关键工厂支持”);
}捕获(InvalidKeySpecException ikse){
Log.e(“AESdemo”,“PBEWITHSHAANDTWOFISH-CBC的密钥规范无效”);
}
//这是我们的密钥。我们可以把它保存到一个文件中,而不是重新生成它
//每次都需要。但该文件不能在设备上(太不安全)。它可能
//如果我们将其保存在可通过https访问的服务器上,请确保安全。
字节[]skAsByteArray=sk.getEncoded()*/
试一试{
skforAES=新的保密密钥规范(密钥生成协议,“AES”);
}捕获(例外e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
最终字符串CIPHERMODEPADDING=“AES/CBC/PKCS7Padding”;
//必须保存IV,以便在需要解密文本时使用
字节[]iv={0xA,1,0xB,5,4,0xF,7,9,0x17,3,1,6,8,0xC,0xD,91};
IvParameterSpec IV=新的IvParameterSpec(IV);
字节[]明文=空;
试一试{
//显然,在实际使用场景中,明文在应用程序中不会是文字。
//这篇纯文本来自刘易斯·卡罗尔的《爱丽丝梦游仙境历险记》第十章
//我喜欢作者强调清楚的解释。。。
纯文本=(
“这是龙虾的声音,我听见他在说”
+“\”你把我烤得太黑了,我得给头发加糖。\“\n”
+“有眼皮的鸭子,有鼻子的鸭子\n”
+“修剪他的腰带和纽扣,把他的脚趾翻出来。”\n”
+“我想让人解释一下,”素甲鱼说
+“她解释不了,”鹰头狮急忙说,“接着读下一节。”
+爱丽丝不敢违抗,尽管她确信一切都会出错
+“她用颤抖的声音继续说:——\n”
+“我经过他的花园,用一只眼睛做了标记,”
+“猫头鹰和黑豹是如何分享馅饼的--'\n”
+“重复这些东西有什么用呢,”素甲鱼插嘴说
+“如果你不在继续解释的话?这是迄今为止我听过的最令人困惑的事情!”
).getBytes(“ISO-8859-1”);
}捕获(不支持的编码异常uee){
Log.e(“AESdemo”,“不支持ISO-8859-1的字符串”);
}
Log.i(“AESdemo”、“明文长度=“+plaintext.length”);
字节[]密文=加密(密文填充、SKFOREAES、IV、明文);
String decrypted=新字符串(解密(CIPHERMODEPADDING、skforAES、IV、密文));
tv1.setText(已解密);
}
//如果要手动添加填充,请使用此方法
//AES以16字节的块处理消息。
//此方法查看消息的长度,并在末尾添加字节
//因此,整个消息是16字节的倍数。
//填充是一系列字节,每个字节都被设置为添加的总字节数(范围为1..16的数字)。
字节[]添加填充(字节[]普通){
字节纯键盘[]=null;
整数短缺=16-(普通长度%16);
//如果已经是16的精确倍数,则需要添加另一个16字节的块
如果(短缺==0)短缺=16;
//将较大的数组重新分配为精确的倍数,添加不足位。
plainpad=新字节[普通长度+短缺]
skforAES = new SecretKeySpec(KEY.getBytes("utf-8"), "AES");