【问题标题】:AES with Base64 key encryption in androidAES 与 Android 中的 Base64 密钥加密
【发布时间】:2012-02-07 10:46:32
【问题描述】:

我正在制作一个 android 应用程序,我应该在其中加密我从用户那里获取的密码并将其发送到我的应用程序引擎。我想使用带有 Base64 密钥的 AES 技术。我是加密/解密的新手,所以我使用了question 中询问的代码。我换了钥匙,换成了我的。这是我的代码:

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”在我加密时会出现此错误。谁能告诉我问题是什么??
-提前致谢

【问题讨论】:

  • 我已将答案作为新代码示例给出,但如果最后一个字符设置了一些低位并且字符串不是,则并非每个使用 base 64 字符集的字符串都自动为 base 64可以被 4 整除,你就有问题了。此外,您可能必须使用 base 64 填充字符 ('=')。
  • 您在 Antrromet 的表现如何,您找到解决方案了吗?如果讨论有点麻烦,我很抱歉:)
  • 嘿 Owlstead,我对加密解密的实验真的很生气,这不是我的一杯茶。所以我使用散列来存储我的密码。
  • 这可能会更好。您可能想查看 PBKDF2 或 bcrypt 以更安全地存储它们(它们可以防止暴力攻击和彩虹表)。当然,它们也更难使用。

标签: java android encryption base64 aes


【解决方案1】:

试试这个作为如何使用字符串作为键和消息的例子。至少它使用正确的(字符)编码,使用 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);
    }
}

【讨论】:

  • DatatypeConverter for Android 的替代方法是什么。我尝试使用 Base64.decode 方法,但它没有给出预期的结果..
  • 我看不到你的机器上发生了什么,YuDroid。请使用DatatypeConverter 的代码和Base64.decode 的代码创建一个新问题,输入和输出,以便我们查看差异。
【解决方案2】:

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是加密密钥

【讨论】:

  • 如果您有任何疑问,请告诉我
  • 是的,这对我有用。但我有一个疑问。实际上,我的朋友们也在做同样的加密工作,但他们得到的结果与我的不同。你能告诉我这是哪种加密/解密技术吗?
  • 加密字符串有特定的格式吗?我需要发送给解密()的参数是什么? decrypt(,) 是否正确?
  • 是的,我明白,但这是哪种技术??我的意思是,即使是我在 iOS 上工作的朋友也使用与我相同的键值,但他们得到了不同的结果。
  • 这个答案中的一切都是错误的。密钥推导,有编码问题,不胜枚举。
【解决方案3】:

看我的回答Android database encryption。它包含 2 个文件,您可以将它们包含在任何需要加密数据存储的应用程序中。有一种实现方法可以更轻松地将字节数组数据转换为可打印的 Base64 数据,反之亦然。使用 AES 算法和密码块链接 (CBC) 加密模式和 PKCS#5 填充。

【讨论】:

    【解决方案4】:

    您好,我重写了没有 DatatypeConverter 和 apache commons 的 owlstead java 方法示例。

    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 上,您可以使用以下使用 Base64 android 类的方法:

    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 "";
    }
    

    希望对您有所帮助!

    【讨论】:

      猜你喜欢
      • 2017-04-16
      • 2012-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多