gpt4 book ai didi

android - 使用 ChaCha20 加密和解密字符串

转载 作者:行者123 更新时间:2023-12-05 00:10:01 24 4
gpt4 key购买 nike

I want to decrypt and encrypt a string using chacha20

BouncyCaSTLeProvider 使用的是 chacha20 技术。所以我把它包括在 jar 里。并尝试了代码但无法工作。

PBE.java

public class PBE extends AppCompatActivity {

private static final String salt = "A long, but constant phrase that will be used each time as the salt.";
private static final int iterations = 2000;
private static final int keyLength = 256;
private static final SecureRandom random = new SecureRandom();

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pbe);

try {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
//Security.addProvider(new BouncyCastleProvider());

String passphrase = "The quick brown fox jumped over the lazy brown dog";
String plaintext = "Hello";
byte [] ciphertext = encrypt(passphrase, plaintext);
String recoveredPlaintext = decrypt(passphrase, ciphertext);

TextView decryptedTv = (TextView) findViewById(R.id.tv_decrypt);

decryptedTv.setText(recoveredPlaintext);

System.out.println(recoveredPlaintext);
}catch (Exception e){
e.printStackTrace();
}

}

private static byte [] encrypt(String passphrase, String plaintext) throws Exception {
SecretKey key = generateKey(passphrase);

Cipher cipher = Cipher.getInstance("AES/CTR/NOPADDING");//,new BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, key, generateIV(cipher), random);
return cipher.doFinal(plaintext.getBytes());
}

private static String decrypt(String passphrase, byte [] ciphertext) throws Exception {
SecretKey key = generateKey(passphrase);

Cipher cipher = Cipher.getInstance("AES/CTR/NOPADDING");// , new BouncyCastleProvider());
cipher.init(Cipher.DECRYPT_MODE, key, generateIV(cipher), random);
return new String(cipher.doFinal(ciphertext));
}

private static SecretKey generateKey(String passphrase) throws Exception {
PBEKeySpec keySpec = new PBEKeySpec(passphrase.toCharArray(), salt.getBytes(), iterations, keyLength);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
return keyFactory.generateSecret(keySpec);
}

private static IvParameterSpec generateIV(Cipher cipher) throws Exception {
byte [] ivBytes = new byte[cipher.getBlockSize()];
random.nextBytes(ivBytes);
return new IvParameterSpec(ivBytes);
}

}

但它没有给我正确的结果..

enter image description here

编辑和更新代码

public class ChaCha20Encryptor implements Encryptor {

private final byte randomIvBytes[] = {0, 1, 2, 3, 4, 5, 6, 7};

static {
Security.addProvider(new BouncyCastleProvider());
}

@Override
public byte[] encrypt(byte[] data, byte[] randomKeyBytes) throws IOException, InvalidKeyException,
InvalidAlgorithmParameterException, InvalidCipherTextException {

ChaChaEngine cipher = new ChaChaEngine();
CipherParameters cp = new KeyParameter(getMyKey(randomKeyBytes));
cipher.init(true, new ParametersWithIV(cp , randomIvBytes));
//cipher.init(true, new ParametersWithIV(new KeyParameter(randomKeyBytes), randomIvBytes));

byte[] result = new byte[data.length];
cipher.processBytes(data, 0, data.length, result, 0);
return result;
}

@Override
public byte[] decrypt(byte[] data, byte[] randomKeyBytes)
throws InvalidKeyException, InvalidAlgorithmParameterException, IOException,
IllegalStateException, InvalidCipherTextException {

ChaChaEngine cipher = new ChaChaEngine();
CipherParameters cp = new KeyParameter(getMyKey(randomKeyBytes));
cipher.init(false, new ParametersWithIV(cp , randomIvBytes));
//cipher.init(false, new ParametersWithIV(new KeyParameter(randomKeyBytes), randomIvBytes));

byte[] result = new byte[data.length];
cipher.processBytes(data, 0, data.length, result, 0);
return result;
}

@Override
public int getKeyLength() {
return 32;
}

@Override
public String toString() {
return "ChaCha20()";
}

private static byte[] getMyKey(byte[] key){
try {
//byte[] key = encodekey.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
}
catch (NoSuchAlgorithmException e){
e.printStackTrace();
}
return key;
}
}

Now I have only problem decrypting. It shows an error that key must be 128 or 256 bits. What am I doing wrong.

最佳答案

2019 年 12 月 24 日更新(更正)

与 AES 中的某些其他模式(如 CBC)不同,GCM 模式不要求 IV 不可预测(与 Chacha20-Poly1305 相同)。唯一的要求是 IV(对于 AES)或 nonce(对于 Chacha20-Poly1305)对于给定 key 的每次调用都必须是唯一的。如果它针对给定 key 重复一次,则可能会危及安全性。以良好的概率实现此目的的一种简单方法是使用来自强伪随机数生成器的随机 IV 或随机数,如下所示。 IV 或 nonce 冲突的概率(假设有一个强随机源)最多为 2^-32,这足以阻止攻击者。

使用序列或时间戳作为 IV 或随机数也是可能的,但它可能不像听起来那么微不足道。例如,如果系统没有正确跟踪已在持久存储中用作 IV 的序列,则调用可能会在系统重启后重复 IV。同样,没有完美的时钟。计算机时钟重新调整等

此外, key 应在每 2^32 次调用后轮换。

SecureRandom.getInstanceStrong()可用于生成加密强度高的随机数。


原始答案

现在支持ChaCha20的是Java 11,下面是一个使用ChaCha20-Poly1305加解密的示例程序。

在 AES-GCM(一种经过身份验证的分组密码算法)上使用 ChaCha20-Poly1305(一种基于流密码的经过身份验证的加密算法)的可能原因是:

  1. 当 CPU 不提供专用 AES 指令时,ChaCha20-Poly1305 几乎比 AES 快 3 倍。 Intel处理器提供AES-NI指令集[1]

  2. 与 AES-GCM 的 IV 不同,ChaCha20-Poly1305 不需要随机数不可预测/随机。因此可以避免运行伪随机数生成器的开销 [2]

  3. ChaCha20 不像 AES [1] 不易受到缓存冲突计时攻击

    package com.sapbasu.javastudy;

    import java.lang.reflect.Field;
    import java.math.BigInteger;
    import java.util.Arrays;
    import java.util.Objects;

    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import javax.security.auth.Destroyable;

    /**
    *
    * The possible reasons for using ChaCha20-Poly1305 which is a
    * stream cipher based authenticated encryption algorithm
    * 1. If the CPU does not provide dedicated AES instructions,
    * ChaCha20 is faster than AES
    * 2. ChaCha20 is not vulnerable to cache-collision timing
    * attacks unlike AES
    * 3. Since the nonce is not required to be random. There is
    * no overhead for generating cryptographically secured
    * pseudo random number
    *
    */

    public class CryptoChaCha20 {

    private static final String ENCRYPT_ALGO = "ChaCha20-Poly1305/None/NoPadding";

    private static final int KEY_LEN = 256;

    private static final int NONCE_LEN = 12; //bytes

    private static final BigInteger NONCE_MIN_VAL = new BigInteger("100000000000000000000000", 16);
    private static final BigInteger NONCE_MAX_VAL = new BigInteger("ffffffffffffffffffffffff", 16);

    private static BigInteger nonceCounter = NONCE_MIN_VAL;

    public static byte[] encrypt(byte[] input, SecretKeySpec key)
    throws Exception {
    Objects.requireNonNull(input, "Input message cannot be null");
    Objects.requireNonNull(key, "key cannot be null");

    if (input.length == 0) {
    throw new IllegalArgumentException("Length of message cannot be 0");
    }

    if (key.getEncoded().length * 8 != KEY_LEN) {
    throw new IllegalArgumentException("Size of key must be 256 bits");
    }

    Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);

    byte[] nonce = getNonce();

    IvParameterSpec ivParameterSpec = new IvParameterSpec(nonce);

    cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);

    byte[] messageCipher = cipher.doFinal(input);

    // Prepend the nonce with the message cipher
    byte[] cipherText = new byte[messageCipher.length + NONCE_LEN];
    System.arraycopy(nonce, 0, cipherText, 0, NONCE_LEN);
    System.arraycopy(messageCipher, 0, cipherText, NONCE_LEN,
    messageCipher.length);
    return cipherText;
    }

    public static byte[] decrypt(byte[] input, SecretKeySpec key)
    throws Exception {
    Objects.requireNonNull(input, "Input message cannot be null");
    Objects.requireNonNull(key, "key cannot be null");

    if (input.length == 0) {
    throw new IllegalArgumentException("Input array cannot be empty");
    }

    byte[] nonce = new byte[NONCE_LEN];
    System.arraycopy(input, 0, nonce, 0, NONCE_LEN);

    byte[] messageCipher = new byte[input.length - NONCE_LEN];
    System.arraycopy(input, NONCE_LEN, messageCipher, 0, input.length - NONCE_LEN);

    IvParameterSpec ivParameterSpec = new IvParameterSpec(nonce);

    Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
    cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);

    return cipher.doFinal(messageCipher);
    }


    /**
    *
    * This method creates the 96 bit nonce. A 96 bit nonce
    * is required for ChaCha20-Poly1305. The nonce is not
    * a secret. The only requirement being it has to be
    * unique for a given key. The following function implements
    * a 96 bit counter which when invoked always increments
    * the counter by one.
    *
    * @return
    */
    public static byte[] getNonce() {
    if (nonceCounter.compareTo(NONCE_MAX_VAL) == -1) {
    return nonceCounter.add(BigInteger.ONE).toByteArray();
    } else {
    nonceCounter = NONCE_MIN_VAL;
    return NONCE_MIN_VAL.toByteArray();
    }
    }
    /**
    *
    * Strings should not be used to hold the clear text message or the key, as
    * Strings go in the String pool and they will show up in a heap dump. For the
    * same reason, the client calling these encryption or decryption methods
    * should clear all the variables or arrays holding the message or the key
    * after they are no longer needed. Since Java 8 does not provide an easy
    * mechanism to clear the key from {@code SecretKeySpec}, this method uses
    * reflection to clear the key
    *
    * @param key
    * The secret key used to do the encryption
    * @throws IllegalArgumentException
    * @throws IllegalAccessException
    * @throws NoSuchFieldException
    * @throws SecurityException
    */
    @SuppressWarnings("unused")
    public static void clearSecret(Destroyable key)
    throws IllegalArgumentException, IllegalAccessException,
    NoSuchFieldException, SecurityException {
    Field keyField = key.getClass().getDeclaredField("key");
    keyField.setAccessible(true);
    byte[] encodedKey = (byte[]) keyField.get(key);
    Arrays.fill(encodedKey, Byte.MIN_VALUE);
    }
    }

并且,这是一个 JUnit 测试:

package com.sapbasu.javastudy;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.security.SecureRandom;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.junit.jupiter.api.Test;

public class CryptoChaCha20Test {

private int KEY_LEN = 256; // bits

@Test
public void whenDecryptCalled_givenEncryptedTest_returnsDecryptedBytes()
throws Exception {

char[] input = {'e', 'n', 'c', 'r', 'y', 'p', 't', 'i', 'o', 'n'};
byte[] inputBytes = convertInputToBytes(input);

KeyGenerator keyGen = KeyGenerator.getInstance("ChaCha20");
keyGen.init(KEY_LEN, SecureRandom.getInstanceStrong());
SecretKey secretKey = keyGen.generateKey();

SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(),
"ChaCha20");
CryptoChaCha20.clearSecret(secretKey);

byte[] encryptedBytes = CryptoChaCha20.encrypt(inputBytes, secretKeySpec);
byte[] decryptedBytes = CryptoChaCha20.decrypt(encryptedBytes, secretKeySpec);

CryptoChaCha20.clearSecret(secretKeySpec);

assertArrayEquals(inputBytes, decryptedBytes);

}

private byte[] convertInputToBytes(char[] input) {
CharBuffer charBuf = CharBuffer.wrap(input);
ByteBuffer byteBuf = Charset.forName(Charset.defaultCharset().name())
.encode(charBuf);
byte[] inputBytes = byteBuf.array();
charBuf.clear();
byteBuf.clear();
return inputBytes;
}
}

关于android - 使用 ChaCha20 加密和解密字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38007478/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com