AES с шифрованием ключа Base64 в Android

Я делаю приложение для Android, в котором я должен шифровать пароли, которые я беру у пользователя, и отправлять их в свой механизм приложения. Я хочу использовать технику AES с ключом Base64. Я новичок в шифровании/дешифровании, поэтому я использовал код, заданный в этом вопросе. Я поменял ключ и заменил его на свой. Это мой код:

public String encrypt(String dataToEncrypt)
            throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        // I'm using AES encription

        if (!dataToEncrypt.equals("")) {
            String key = "rEqrHrhdd9I1sg==";

            Cipher c = Cipher.getInstance("AES");
            SecretKeySpec k;
            try {
                k = new SecretKeySpec(key.getBytes(), "AES");
                c.init(Cipher.ENCRYPT_MODE, k);
            } catch (Exception e) {
                e.printStackTrace();
            }

            return new String(c.doFinal(Base64.decode(dataToEncrypt, 0)));
        }
        return "";
    }

Но иногда я получаю сообщение об ошибке java.lang.IllegalArgumentException: bad base-64, когда я пытаюсь зашифровать определенные строки, скажем, asdasdasd выдает эту ошибку, когда я ее шифрую. Кто-нибудь может сказать мне, в чем проблема??
- Заранее спасибо


person Antrromet    schedule 07.02.2012    source источник
comment
Я дал ответ как новый образец кода, но не каждая строка, использующая набор символов base 64, автоматически является base 64, если в последнем символе установлены некоторые младшие биты, а строка не делится на 4, у вас есть проблемы . Кроме того, вам, возможно, придется использовать символ заполнения base 64 ('=').   -  person Maarten Bodewes    schedule 10.02.2012
comment
Как дела, Антромет, вы нашли решение? Извините, если дискуссия зашла слишком далеко :)   -  person Maarten Bodewes    schedule 12.02.2012
comment
Привет, Оулстед, меня очень бесят эксперименты с расшифровкой шифрования, это не моя чашка чая. Поэтому вместо этого я использую хеширование для хранения своих паролей.   -  person Antrromet    schedule 13.02.2012
comment
Это, наверное, все же лучше. Возможно, вы захотите проверить PBKDF2 или bcrypt, чтобы хранить их еще более безопасно (они защищают от атак грубой силы и радужных таблиц). Конечно, они также немного сложнее в использовании.   -  person Maarten Bodewes    schedule 13.02.2012


Ответы (4)


Попробуйте это в качестве примера того, как использовать строки для ключей и сообщений. По крайней мере, он использует правильную (символьную) кодировку, использует режим CBC и заполнение PKCS5/7. Обратите внимание, что существует множество проблем с отправкой зашифрованных паролей на сервер. Обычно безопасность достигается за счет использования SSL для конфиденциальности и bcrypt или PBKDF2 на сервере (но это снова и снова обсуждалось в stackoverflow).

Обратите внимание, что приведенный ниже код не обеспечивает проверки целостности или подлинности.

public static String encrypt(final String plainMessage,
        final String symKeyHex) {
    final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex);

    final byte[] encodedMessage = plainMessage.getBytes(Charset
            .forName("UTF-8"));
    try {
        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // generate random IV using block size (possibly create a method for
        // this)
        final byte[] ivData = new byte[blockSize];
        final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
        rnd.nextBytes(ivData);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        cipher.init(Cipher.ENCRYPT_MODE, symKey, iv);

        final byte[] encryptedMessage = cipher.doFinal(encodedMessage);

        // concatenate IV and encrypted message
        final byte[] ivAndEncryptedMessage = new byte[ivData.length
                + encryptedMessage.length];
        System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
        System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage,
                blockSize, encryptedMessage.length);

        final String ivAndEncryptedMessageBase64 = DatatypeConverter
                .printBase64Binary(ivAndEncryptedMessage);

        return ivAndEncryptedMessageBase64;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during encryption", e);
    }
}

public static String decrypt(final String ivAndEncryptedMessageBase64,
        final String symKeyHex) {
    final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex);

    final byte[] ivAndEncryptedMessage = DatatypeConverter
            .parseBase64Binary(ivAndEncryptedMessageBase64);
    try {
        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // retrieve random IV from start of the received message
        final byte[] ivData = new byte[blockSize];
        System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        // retrieve the encrypted message itself
        final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length
                - blockSize];
        System.arraycopy(ivAndEncryptedMessage, blockSize,
                encryptedMessage, 0, encryptedMessage.length);

        cipher.init(Cipher.DECRYPT_MODE, symKey, iv);

        final byte[] encodedMessage = cipher.doFinal(encryptedMessage);

        // concatenate IV and encrypted message
        final String message = new String(encodedMessage,
                Charset.forName("UTF-8"));

        return message;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (BadPaddingException e) {
        // you'd better know about padding oracle attacks
        return null;
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during decryption", e);
    }
}
person Maarten Bodewes    schedule 10.02.2012
comment
Какова альтернатива использованию DatatypeConverter для Android. Я попытался использовать метод Base64.decode, но он не дал ожидаемого результата. - person YuDroid; 18.02.2014
comment
Я не вижу, что происходит на твоей машине, ЮДроид. Пожалуйста, создайте новый вопрос с кодом DatatypeConverter и с кодом Base64.decode, вводом и выводом, чтобы мы могли увидеть различия. - person Maarten Bodewes; 18.02.2014

Simplecrypto.java

     import java.security.SecureRandom;
     import javax.crypto.Cipher;
     import javax.crypto.KeyGenerator;
     import javax.crypto.SecretKey;
     import javax.crypto.spec.SecretKeySpec;

     public class SimpleCrypto {

public  String encrypt(String seed, String cleartext) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] result = encrypt(rawKey, cleartext.getBytes());
        return toHex(result);
}

public  String decrypt(String seed, String encrypted) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] enc = toByte(encrypted);
        byte[] result = decrypt(rawKey, enc);
        return new String(result);
}

//done
private  byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
        sr.setSeed(seed);
    kgen.init(128, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
}


private  byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(clear);
        return encrypted;
}

private  byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;
}

public  String toHex(String txt) {
        return toHex(txt.getBytes());
}
public  String fromHex(String hex) {
        return new String(toByte(hex));
}

public  byte[] toByte(String hexString) {
        int len = hexString.length()/2;
        byte[] result = new byte[len];
        for (int i = 0; i < len; i++)
                result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
        return result;
}

public  String toHex(byte[] buf) {
        if (buf == null)
                return "";
        StringBuffer result = new StringBuffer(2*buf.length);
        for (int i = 0; i < buf.length; i++) {
                appendHex(result, buf[i]);
        }
        return result.toString();
}
private final static String HEX = "0123456789ABCDEF";
private  void appendHex(StringBuffer sb, byte b) {
        sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}

  }

и в действии введите следующий код:

SimpleCrypto simpleCrypto = new SimpleCrypto();
    String s = "";
    try {
        s = simpleCrypto.encrypt("abc", "xyz");
    } catch (Exception e) {
        e.printStackTrace();
    }

abc — это текст, который нужно зашифровать, а xyz — ключ для шифрования.

person Ramesh Solanki    schedule 07.02.2012
comment
дайте мне знать, если у вас есть какие-либо сомнения - person Ramesh Solanki; 07.02.2012
comment
да, это работает для меня. Но у меня есть сомнения. На самом деле мои друзья тоже работают над тем же шифрованием, но получают другой результат, чем мой. Не могли бы вы сказать мне, что именно это за метод шифрования/дешифрования? - person Antrromet; 07.02.2012
comment
Существует ли определенный формат зашифрованной строки?? и какие параметры мне нужно отправить в расшифровку () ?? Правильно ли расшифровать(‹расшифрованный текст›,‹ключ›)? - person Antrromet; 07.02.2012
comment
да я понимаю это, но что это за техника?? Я имею в виду, что даже мои друзья, работающие над iOS, используют то же значение ключа, что и мое, но получают другой результат. - person Antrromet; 07.02.2012
comment
В этом ответе ВСЕ неправильно. Вывод ключа, проблемы с кодировкой, список можно продолжить. - person Maarten Bodewes; 10.02.2012
comment
Рамеш: ты не можешь продолжать в том же духе, тебе нужно обсудить с друзьями, какой именно протокол использовать. Это должно включать в себя шифр (AES с размером ключа 128 бит, OK), затем режим, тип заполнения, который будет использоваться, и (символьное) кодирование как обычного текста, так и зашифрованного текста. CBC с добавленным IV был бы хорошим стартером (см. Мой ответ). Только зная все параметры, можно приступать к разработке (возможно, можно поделиться этим в коде, но это нужно знать заранее). - person Maarten Bodewes; 12.02.2012

Посмотрите мой ответ здесь Шифрование базы данных Android. Он содержит 2 файла, которые вы можете включить в любое из ваших приложений, требующих шифрования хранилища данных. Реализован метод, упрощающий преобразование данных байтового массива в печатные данные Base64 и наоборот. Используется алгоритм AES с режимом шифрования Cipher Block Chaining (CBC) и дополнением PKCS#5.

person Plo_Koon    schedule 24.11.2013

Привет, я переписываю пример java-методов owlstead без DatatypeConverter и с apache commons.

public static String encrypt(final String plainMessage,
        final String symKeyHex) {


    try {

    final byte[] symKeyData = Hex.decodeHex(symKeyHex.toCharArray());

    final byte[] encodedMessage = plainMessage.getBytes(Charset.forName("UTF-8"));

        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // generate random IV using block size (possibly create a method for
        // this)
        final byte[] ivData = new byte[blockSize];
        final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
        rnd.nextBytes(ivData);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        cipher.init(Cipher.ENCRYPT_MODE, symKey, iv);

        final byte[] encryptedMessage = cipher.doFinal(encodedMessage);

        // concatenate IV and encrypted message
        final byte[] ivAndEncryptedMessage = new byte[ivData.length
                + encryptedMessage.length];
        System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
        System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage,
                blockSize, encryptedMessage.length);

        final String ivAndEncryptedMessageBase64 = Base64.encodeBase64String(ivAndEncryptedMessage);

        return ivAndEncryptedMessageBase64;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during encryption", e);
    } catch (DecoderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return "";

}

public static String decrypt(final String ivAndEncryptedMessageBase64,
        final String symKeyHex) {

    try {
        final byte[] symKeyData = Hex.decodeHex(symKeyHex.toCharArray());
        final byte[] ivAndEncryptedMessage = Base64.decodeBase64(ivAndEncryptedMessageBase64);


        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // retrieve random IV from start of the received message
        final byte[] ivData = new byte[blockSize];
        System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        // retrieve the encrypted message itself
        final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length
                - blockSize];
        System.arraycopy(ivAndEncryptedMessage, blockSize,
                encryptedMessage, 0, encryptedMessage.length);

        cipher.init(Cipher.DECRYPT_MODE, symKey, iv);

        final byte[] encodedMessage = cipher.doFinal(encryptedMessage);

        // concatenate IV and encrypted message
        final String message = new String(encodedMessage,
                Charset.forName("UTF-8"));

        return message;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (BadPaddingException e) {
        // you'd better know about padding oracle attacks
        return null;
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during decryption", e);
    } catch (DecoderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return "";
}

Вы даже не можете использовать это на Android, потому что у вас могут быть проблемы с классом Base64. На Android вы можете использовать следующие методы, использующие класс Android Base64:

public static String encrypt(final String plainMessage,
                             final String symKeyHex) {


    try {

        final byte[] symKeyData = Hex.decodeHex(symKeyHex.toCharArray());

        final byte[] encodedMessage = plainMessage.getBytes(Charset.forName("UTF-8"));

        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // generate random IV using block size (possibly create a method for
        // this)
        final byte[] ivData = new byte[blockSize];
        final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
        rnd.nextBytes(ivData);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        cipher.init(Cipher.ENCRYPT_MODE, symKey, iv);

        final byte[] encryptedMessage = cipher.doFinal(encodedMessage);

        // concatenate IV and encrypted message
        final byte[] ivAndEncryptedMessage = new byte[ivData.length
                + encryptedMessage.length];
        System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
        System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage,
                blockSize, encryptedMessage.length);

        //final String ivAndEncryptedMessageBase64 = Base64.encodeBase64String(ivAndEncryptedMessage);
        final String ivAndEncryptedMessageBase64 = Base64.encodeToString(ivAndEncryptedMessage,Base64.DEFAULT);

        return ivAndEncryptedMessageBase64;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during encryption", e);
    } catch (DecoderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return "";

}

public static String decrypt(final String ivAndEncryptedMessageBase64,
                             final String symKeyHex) {


    try {

        final byte[] symKeyData = Hex.decodeHex(symKeyHex.toCharArray());
        //final byte[] ivAndEncryptedMessage = Base64.decodeBase64(ivAndEncryptedMessageBase64);
        final byte[] ivAndEncryptedMessage = Base64.decode(ivAndEncryptedMessageBase64,Base64.DEFAULT);

        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();

        // create the key
        final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");

        // retrieve random IV from start of the received message
        final byte[] ivData = new byte[blockSize];
        System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
        final IvParameterSpec iv = new IvParameterSpec(ivData);

        // retrieve the encrypted message itself
        final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length
                - blockSize];
        System.arraycopy(ivAndEncryptedMessage, blockSize,
                encryptedMessage, 0, encryptedMessage.length);

        cipher.init(Cipher.DECRYPT_MODE, symKey, iv);

        final byte[] encodedMessage = cipher.doFinal(encryptedMessage);

        // concatenate IV and encrypted message
        final String message = new String(encodedMessage,
                Charset.forName("UTF-8"));

        return message;
    } catch (InvalidKeyException e) {
        throw new IllegalArgumentException(
                "key argument does not contain a valid AES key");
    } catch (BadPaddingException e) {
        // you'd better know about padding oracle attacks
        return null;
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(
                "Unexpected exception during decryption", e);
    } catch (DecoderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return "";
}

Надеюсь, это поможет!

person alessandro    schedule 12.03.2014