gpt4 book ai didi

android - Android 4.2 上的加密错误

转载 作者:行者123 更新时间:2023-12-01 04:34:22 24 4
gpt4 key购买 nike

以下代码适用于除最新 4.2 之外的所有 Android 版本

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
* Util class to perform encryption/decryption over strings. <br/>
*/
public final class UtilsEncryption
{
/** The logging TAG */
private static final String TAG = UtilsEncryption.class.getName();

/** */
private static final String KEY = "some_encryption_key";

/**
* Avoid instantiation. <br/>
*/
private UtilsEncryption()
{
}

/** The HEX characters */
private final static String HEX = "0123456789ABCDEF";

/**
* Encrypt a given string. <br/>
*
* @param the string to encrypt
* @return the encrypted string in HEX
*/
public static String encrypt( String cleartext )
{
try
{
byte[] result = process( Cipher.ENCRYPT_MODE, cleartext.getBytes() );
return toHex( result );
}
catch ( Exception e )
{
System.out.println( TAG + ":encrypt:" + e.getMessage() );
}
return null;
}

/**
* Decrypt a HEX encrypted string. <br/>
*
* @param the HEX string to decrypt
* @return the decrypted string
*/
public static String decrypt( String encrypted )
{
try
{
byte[] enc = fromHex( encrypted );
byte[] result = process( Cipher.DECRYPT_MODE, enc );
return new String( result );
}
catch ( Exception e )
{
System.out.println( TAG + ":decrypt:" + e.getMessage() );
}
return null;
}


/**
* Get the raw encryption key. <br/>
*
* @param the seed key
* @return the raw key
* @throws NoSuchAlgorithmException
*/
private static byte[] getRawKey()
throws NoSuchAlgorithmException
{
KeyGenerator kgen = KeyGenerator.getInstance( "AES" );
SecureRandom sr = SecureRandom.getInstance( "SHA1PRNG" );
sr.setSeed( KEY.getBytes() );
kgen.init( 128, sr );
SecretKey skey = kgen.generateKey();
return skey.getEncoded();
}

/**
* Process the given input with the provided mode. <br/>
*
* @param the cipher mode
* @param the value to process
* @return the processed value as byte[]
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
*/
private static byte[] process( int mode, byte[] value )
throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException,
NoSuchPaddingException
{
SecretKeySpec skeySpec = new SecretKeySpec( getRawKey(), "AES" );
Cipher cipher = Cipher.getInstance( "AES" );
cipher.init( mode, skeySpec );
byte[] encrypted = cipher.doFinal( value );
return encrypted;
}

/**
* Decode an HEX encoded string into a byte[]. <br/>
*
* @param the HEX string value
* @return the decoded byte[]
*/
protected static byte[] fromHex( String value )
{
int len = value.length() / 2;
byte[] result = new byte[len];
for ( int i = 0; i < len; i++ )
{
result[i] = Integer.valueOf( value.substring( 2 * i, 2 * i + 2 ), 16 ).byteValue();
}
return result;
}

/**
* Encode a byte[] into an HEX string. <br/>
*
* @param the byte[] value
* @return the HEX encoded string
*/
protected static String toHex( byte[] value )
{
if ( value == null )
{
return "";
}
StringBuffer result = new StringBuffer( 2 * value.length );
for ( int i = 0; i < value.length; i++ )
{
byte b = value[i];

result.append( HEX.charAt( ( b >> 4 ) & 0x0f ) );
result.append( HEX.charAt( b & 0x0f ) );
}
return result.toString();
}
}

这是我创建的一个小型单元测试,用于重现错误

import junit.framework.TestCase;

public class UtilsEncryptionTest
extends TestCase
{
/** A random string */
private static String ORIGINAL = "some string to test";

/**
* The HEX value corresponds to ORIGINAL. <br/>
* If you change ORIGINAL, calculate the new value on one of this sites:
* <ul>
* <li>http://www.string-functions.com/string-hex.aspx</li>
* <li>http://www.yellowpipe.com/yis/tools/encrypter/index.php</li>
* <li>http://www.convertstring.com/EncodeDecode/HexEncode</li>
* </ul>
*/
private static String HEX = "736F6D6520737472696E6720746F2074657374";

public void testToHex()
{
String hexString = UtilsEncryption.toHex( ORIGINAL.getBytes() );

assertNotNull( "The HEX string should not be null", hexString );
assertTrue( "The HEX string should not be empty", hexString.length() > 0 );
assertEquals( "The HEX string was not encoded correctly", HEX, hexString );
}

public void testFromHex()
{
byte[] stringBytes = UtilsEncryption.fromHex( HEX );

assertNotNull( "The HEX string should not be null", stringBytes );
assertTrue( "The HEX string should not be empty", stringBytes.length > 0 );
assertEquals( "The HEX string was not encoded correctly", ORIGINAL, new String( stringBytes ) );
}

public void testWholeProcess()
{
String encrypted = UtilsEncryption.encrypt( ORIGINAL );
assertNotNull( "The encrypted result should not be null", encrypted );
assertTrue( "The encrypted result should not be empty", encrypted.length() > 0 );

String decrypted = UtilsEncryption.decrypt( encrypted );
assertNotNull( "The decrypted result should not be null", decrypted );
assertTrue( "The decrypted result should not be empty", decrypted.length() > 0 );

assertEquals( "Something went wrong", ORIGINAL, decrypted );
}

}

抛出异常的行是:

byte[] encrypted = cipher.doFinal( value );

完整的堆栈跟踪是:

    W/<package>.UtilsEncryption:decrypt(16414): pad block corrupted
W/System.err(16414): javax.crypto.BadPaddingException: pad block corrupted
W/System.err(16414): at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCipher.java:709)
W/System.err(16414): at javax.crypto.Cipher.doFinal(Cipher.java:1111)
W/System.err(16414): at <package>.UtilsEncryption.process(UtilsEncryption.java:117)
W/System.err(16414): at <package>.UtilsEncryption.decrypt(UtilsEncryption.java:69)
W/System.err(16414): at <package>.UtilsEncryptionTest.testWholeProcess(UtilsEncryptionTest.java:74)
W/System.err(16414): at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err(16414): at java.lang.reflect.Method.invoke(Method.java:511)
W/System.err(16414): at junit.framework.TestCase.runTest(TestCase.java:168)
W/System.err(16414): at junit.framework.TestCase.runBare(TestCase.java:134)
W/System.err(16414): at junit.framework.TestResult$1.protect(TestResult.java:115)
W/System.err(16414): at junit.framework.TestResult.runProtected(TestResult.java:133)
D/elapsed ( 588): 14808
W/System.err(16414): at junit.framework.TestResult.run(TestResult.java:118)
W/System.err(16414): at junit.framework.TestCase.run(TestCase.java:124)
W/System.err(16414): at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:190)
W/System.err(16414): at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:175)
W/System.err(16414): at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)
W/System.err(16414): at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1661)

有人知道可能发生什么吗?有人知道 android 4.2 在任何引用的类中发生了重大变化吗?

非常感谢

最佳答案

来自Android Jellybean page :

Modified the default implementations of SecureRandom and Cipher.RSA to use OpenSSL

他们更改了 SecureRandom 的默认提供程序,以使用 OpenSSL 而不是以前的加密提供程序。

以下代码将在 Android 4.2 之前的版本和 Android 4.2 上产生两个不同的输出:

SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
Log.i(TAG, "rand.getProvider(): " + rand.getProvider().getName());

在 4.2 之前的设备上:

rand.getProvider: Crypto

在 4.2 设备上:

rand.getProvider: AndroidOpenSSL

幸运的是,很容易恢复到旧的行为:

SecureRandom sr = SecureRandom.getInstance( "SHA1PRNG", "Crypto" );

可以肯定的是,根据 Javadocs 调用 SecureRandom.setSeed 是很危险的。哪个州:

Seeding SecureRandom may be insecure

A seed is an array of bytes used to bootstrap random number generation. To produce cryptographically secure random numbers, both the seed and the algorithm must be secure.

By default, instances of this class will generate an initial seed using an internal entropy source, such as /dev/urandom. This seed is unpredictable and appropriate for secure use.

You may alternatively specify the initial seed explicitly with the seeded constructor or by calling setSeed(byte[]) before any random numbers have been generated. Specifying a fixed seed will cause the instance to return a predictable sequence of numbers. This may be useful for testing but it is not appropriate for secure use.

但是,对于编写单元测试(正如您所做的那样),使用 setSeed 可能没问题。

关于android - Android 4.2 上的加密错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17540208/

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