Related
I‘m a rookie in PointyCastle,how can I generate ecc base64 key pairs with PointyCastle in dart
AsymmetricKeyPair<PublicKey, PrivateKey> generateKeyPair({curve = 'secp256r1'}) {
var param = curve == 'secp256r1' ? ECCurve_secp256r1() : ECCurve_secp256k1();
var keyParams = ECKeyGeneratorParameters(param);
var random = FortunaRandom();
random.seed(KeyParameter(_seed()));
var generator = ECKeyGenerator();
generator.init(ParametersWithRandom(keyParams, random));
return generator.generateKeyPair();
}
Uint8List _seed() {
var random = Random.secure();
var seed = List<int>.generate(32, (_) => random.nextInt(256));
return Uint8List.fromList(seed);
}
above I can generate a AsymmetricKeyPair object,how to get public base64 and private base64 like my already done js bundle
{"priKey":"CVK3r/UxdGCwQBjtn5vN/orUMxKf9E/1TlJzLkMz9t4=","pubKey":"BJH/mWJqgchGxXGA5/E79SsWRwVo3rpduBmD8FOs7UlKiK8PIvwrkCDvUcwhKdysW35OByPjoVcwFqg1NyumLKM="}
besides, at first I want to use my js bundle file in flutter android, but that would be very tough as I know
how to use js bundle in flutter android
I also need to make sign and verify function with ecdsa in sha256
Signer signer = new Signer('SHA-256/ECDSA');
// 签名,参数:私钥,明文
ECSignature sign(String privateKeyStr, String txt) {
SecureRandom random = _setRadom();
// how to convert a plain txt to kTestBytes
final Uint8List kTestBytes = new Uint8List.fromList([1, 2, 3]);
// if I pass in base64 privateKey str, is the radix 64?
ECPrivateKey privateKey = new ECPrivateKey(BigInt.parse(privateKeyStr, radix: 10), ecDomain);
PrivateKeyParameter signParams = new PrivateKeyParameter(privateKey);
signer.init(true, new ParametersWithRandom(signParams, random));
ECSignature signature = signer.generateSignature(kTestBytes) as ECSignature;
return signature;
}
// 验签
// 参数: 明文,签名,公钥
bool verify(txt, signature, publicKey) {
// how to make the txt to kTestBytes
var kTestBytes = txt
signer.init(false, new PublicKeyParameter(publicKey));
bool verify = signer.verifySignature(kTestBytes, signature);
// print(verify);
return verify;
}
// I don't know what this function actually do,as I know in other language ecdsa don;t need a random number.
SecureRandom _setRadom() {
List<int> key = [67, 3, 241, 75, 143, 78, 115, 99, 21, 242, 180, 43, 26, 7, 194, 20];
List<int> iv = [87, 117, 137, 182, 2, 199, 132, 230, 120, 12, 109, 177, 34, 197, 186, 206];
KeyParameter keyParam = new KeyParameter(new Uint8List.fromList(key));
ParametersWithIV<KeyParameter> paramsIV = new ParametersWithIV(keyParam, new Uint8List.fromList(iv));
SecureRandom random = new SecureRandom('AES/CTR/AUTO-SEED-PRNG')..seed(paramsIV);
return random;
}
Any place can I find sample codes, these functions were changed by some copies on the internet。and I got many confuses list in the comment
The EC keys are to be exported/imported as a Base64 encoded raw private key and as a Base64 encoded raw uncompressed public key.
First of all it can be stated that signing and verifying with the posted code works when a fresh key pair is generated:
AsymmetricKeyPair<PublicKey, PrivateKey> kp = generateKeyPair();
ECSignature signature = sign(kp.privateKey as ECPrivateKey, "The quick brown fox jumps over the lazy dog");
bool verified = verify("The quick brown fox jumps over the lazy dog", signature, kp.publicKey as ECPublicKey);
print(verified); // true
I.e. in the following I will focus on the import/export of the keys. The raw keys are encapsulated in ECPrivateKey and ECPublicKey and can be exported and imported as follows:
String p256 = 'secp256r1';
AsymmetricKeyPair<PublicKey, PrivateKey> kp = generateKeyPair(curve: p256);
// Export
BigInt d = (kp.privateKey as ECPrivateKey).d!;
BigInt x = (kp.publicKey as ECPublicKey).Q!.x!.toBigInteger()!;
BigInt y = (kp.publicKey as ECPublicKey).Q!.y!.toBigInteger()!;
// Import
ECDomainParameters domain = ECDomainParameters(p256);
ECPrivateKey ecPrivateKey = ECPrivateKey(d, domain);
ECPublicKey ecPublicKey = ECPublicKey(domain.curve.createPoint(x, y), domain);
Here d is the raw private key and x and y are the x and y coordinates of the raw public key.
On the JavaScript side, the Base64 encoded raw private key is used and the Base64 encoded raw uncompressed key, where the uncompressed key is the concatenation 0x04 + <x> + <y>. So, for export and import, the following applies:
Regarding the export, the Base64 encoded raw private and public key can be derived from d, x, and y as follows:
String rawPrivateB64 = exportPrivate(d);
String rawUncompressedPublicB64 = exportPublic(x, y, 32);
with
import 'dart:convert';
import 'package:nanodart/nanodart.dart';
String exportPrivate(BigInt d){
return base64Encode(NanoHelpers.bigIntToBytes(d));
}
String exportPublic(BigInt x, BigInt y, int size){
return base64Encode(NanoHelpers.concat([Uint8List.fromList([4]), pad(NanoHelpers.bigIntToBytes(x), size), pad(NanoHelpers.bigIntToBytes(y), size)]));
}
Uint8List pad(Uint8List list, int size){
Uint8List padded = list;
int currSize = list.length;
if (currSize < size){
Uint8List pad = Uint8List(size - currSize);
padded = NanoHelpers.concat([pad, list]);
}
return padded;
}
The size passed in exportPublic() as 3rd parameter is the size of the order of the generator point (32 bytes for secp256r1). If x or y are smaller, they are each padded from the front with 0x00 values until the required length is reached.
For the conversion from BigInt to Uint8List and the concatenation I used the NanoHelpers class from the NanoDart package for simplicity. Of course, other implementations can be used here as well.
Regarding the import, d, x, and y can be derived from the Base64 encoded raw private and public key as follows:
BigInt d = importPrivate(rawPrivateB64);
List xy = importPublic(rawUncompressedPublicB64);
BigInt x = xy.elementAt(0);
BigInt y = xy.elementAt(1);
with
BigInt importPrivate(String d){
return NanoHelpers.byteToBigInt(base64Decode(d));
}
List importPublic(String xy){
Uint8List xyBytes = base64Decode(xy);
xyBytes = xyBytes.sublist(1, xyBytes.length);
int size = xyBytes.length ~/ 2;
Uint8List x = xyBytes.sublist(0, size);
Uint8List y = xyBytes.sublist(size);
return [NanoHelpers.byteToBigInt(x), NanoHelpers.byteToBigInt(y)];
}
Test
The posted key pair
{"priKey":"CVK3r/UxdGCwQBjtn5vN/orUMxKf9E/1TlJzLkMz9t4=","pubKey":"BJH/mWJqgchGxXGA5/E79SsWRwVo3rpduBmD8FOs7UlKiK8PIvwrkCDvUcwhKdysW35OByPjoVcwFqg1NyumLKM="}
can be imported and used for signing and verification as follows:
String rawPrivateB64 = "CVK3r/UxdGCwQBjtn5vN/orUMxKf9E/1TlJzLkMz9t4=";
String rawUncompressedPublicB64 = "BJH/mWJqgchGxXGA5/E79SsWRwVo3rpduBmD8FOs7UlKiK8PIvwrkCDvUcwhKdysW35OByPjoVcwFqg1NyumLKM=";
BigInt d = importPrivate(rawPrivateB64);
List xy = importPublic(rawUncompressedPublicB64);
BigInt x = xy.elementAt(0);
BigInt y = xy.elementAt(1);
ECDomainParameters domain = ECDomainParameters('secp256r1');
ECPrivateKey private = ECPrivateKey(d, domain);
ECPublicKey public = ECPublicKey(domain.curve.createPoint(x, y), domain);
ECSignature signature = sign(private, "The quick brown fox jumps over the lazy dog");
bool verified = verify("The quick brown fox jumps over the lazy dog", signature, public);
print(verified); // true
Edit:
Regarding your comment: sign() and verify() are the methods you posted, but according to the changes, the keys are now passed directly (instead of strings) and the actual message is applied (instead of [1,2,3]) using utf8.encode() for UTF-8 encoding:
import 'dart:convert';
ECSignature sign(ECPrivateKey privateKey, String txt) {
SecureRandom random = _setRandom();
Uint8List txtBytes = Uint8List.fromList(utf8.encode(txt));
PrivateKeyParameter signParams = PrivateKeyParameter(privateKey);
signer.init(true, ParametersWithRandom(signParams, random));
ECSignature signature = signer.generateSignature(txtBytes) as ECSignature;
return signature;
}
bool verify(String txt, ECSignature signature, ECPublicKey publicKey) {
signer.init(false, PublicKeyParameter(publicKey));
bool verify = signer.verifySignature(Uint8List.fromList(utf8.encode(txt)), signature);
return verify;
}
As _setRandom() I applied the implementation from generateKeyPair() instead of your implementation (i.e. a FortunaRandom() based CSPRNG).
my whole code based on accepted answer
crypto.dart
import "dart:typed_data";
import "dart:math";
import 'dart:convert';
import "package:pointycastle/export.dart";
import './utils.dart';
Signer signer = new Signer('SHA-256/ECDSA');
class Crypto {
final ECDomainParameters ecDomain = new ECDomainParameters('secp256r1');
/// 公私钥对生成
/// 关于公私钥encoding:https://stackoverflow.com/questions/72641616/how-to-convert-asymmetrickeypair-to-base64-encoding-string-in-dart
///
Map generateKeyPair({curve = 'secp256r1'}) {
var param = curve == 'secp256r1' ? ECCurve_secp256r1() : ECCurve_secp256k1();
var keyParams = ECKeyGeneratorParameters(param);
var random = FortunaRandom();
random.seed(KeyParameter(this._seed(32)));
var generator = ECKeyGenerator();
generator.init(ParametersWithRandom(keyParams, random));
AsymmetricKeyPair<PublicKey, PrivateKey> kp = generator.generateKeyPair();
BigInt d = (kp.privateKey as ECPrivateKey).d!;
BigInt x = (kp.publicKey as ECPublicKey).Q!.x!.toBigInteger()!;
BigInt y = (kp.publicKey as ECPublicKey).Q!.y!.toBigInteger()!;
String rawPrivateB64 = exportPrivate(d);
String rawUncompressedPublicB64 = exportPublic(x, y, 32);
return {'base64Pub': rawUncompressedPublicB64, 'base64Priv': rawPrivateB64};
}
Uint8List _seed(size) {
var random = Random.secure();
var seed = List<int>.generate(size, (_) => random.nextInt(256));
return Uint8List.fromList(seed);
}
// TODO
// Restore the ECPrivateKey from 'd'.
restoreKeyFromPrivate(privateKeyStr) {
ECPrivateKey privateKey = new ECPrivateKey(BigInt.parse(privateKeyStr, radix: 10), ecDomain);
ECPoint Q = privateKey.parameters!.G * privateKey.d as ECPoint;
ECPublicKey publicKey = new ECPublicKey(Q, privateKey.parameters);
return publicKey;
}
ECSignature sign(ECPrivateKey privateKey, String txt) {
SecureRandom random = _setRandom();
Uint8List txtBytes = Uint8List.fromList(utf8.encode(txt));
PrivateKeyParameter signParams = PrivateKeyParameter(privateKey);
signer.init(true, ParametersWithRandom(signParams, random));
ECSignature signature = signer.generateSignature(txtBytes) as ECSignature;
return signature;
}
bool verify(String txt, ECSignature signature, ECPublicKey publicKey) {
signer.init(false, PublicKeyParameter(publicKey));
bool verify = signer.verifySignature(Uint8List.fromList(utf8.encode(txt)), signature);
return verify;
}
SecureRandom _setRandom() {
// List<int> key = [67, 3, 241, 75, 143, 78, 115, 99, 21, 242, 180, 43, 26, 7, 194, 20];
// List<int> iv = [87, 117, 137, 182, 2, 199, 132, 230, 120, 12, 109, 177, 34, 197, 186, 206];
List<int> key = _seed(16);
List<int> iv = _seed(16);
KeyParameter keyParam = new KeyParameter(new Uint8List.fromList(key));
ParametersWithIV<KeyParameter> paramsIV = new ParametersWithIV(keyParam, new Uint8List.fromList(iv));
SecureRandom random = new SecureRandom('AES/CTR/AUTO-SEED-PRNG')..seed(paramsIV);
return random;
}
}
crypto_test.dart
import '../lib/crypto/crypto.dart';
import "dart:typed_data";
import "dart:math";
import '../lib/crypto/utils.dart';
import "package:pointycastle/export.dart";
var crypto = new Crypto();
void main() {
// _generateTest();
// _signTest();
Map keyPair = crypto.generateKeyPair();
String rawPrivateB64 = keyPair['base64Priv'];
String rawUncompressedPublicB64 = keyPair['base64Pub'];
BigInt d = importPrivate(rawPrivateB64);
List xy = importPublic(rawUncompressedPublicB64);
BigInt x = xy.elementAt(0);
BigInt y = xy.elementAt(1);
ECDomainParameters domain = ECDomainParameters('secp256r1');
ECPrivateKey private = ECPrivateKey(d, domain);
ECPublicKey public = ECPublicKey(domain.curve.createPoint(x, y), domain);
ECSignature signature = crypto.sign(private, "The quick brown fox jumps over the lazy dog");
bool verified = crypto.verify("The quick brown fox jumps over the lazy dog", signature, public);
print('验签结果');
print(verified); // true
}
_generateTest() {
Map keyPair = crypto.generateKeyPair();
print("结果");
print(keyPair['base64Pub']);
print(keyPair['base64Priv']);
}
_signTest() {
// AsymmetricKeyPair<PublicKey, PrivateKey> kp = crypto.generateKeyPair();
// ECSignature signature = sign(kp.privateKey as ECPrivateKey, "The quick brown fox jumps over the lazy dog");
// bool verified = crypto.verify("The quick brown fox jumps over the lazy dog", signature, kp.publicKey as ECPublicKey);
// print(verified); // true
}
I am using OPTEE-OS and mbedTLS and want to create a CSR. I am creating my EC key using the Global Platform API:
res = TEE_AllocateTransientObject(
TEE_TYPE_ECDSA_KEYPAIR,
DSEC_ECDSA_SHA256_KEY_BITS,
&key_pair);
if (res != TEE_SUCCESS) {
return res;
}
Then extract the private key:
res = TEE_GetObjectBufferAttribute(
key_pair,
TEE_ATTR_ECC_PRIVATE_VALUE,
buffer,
&bufferlen);
if (res != TEE_SUCCESS) {
return res;
}
Then use mbedTLS to parse this value and create a to create a CSR:
mbedtls_pk_context priv_key;
mbedtls_pk_init(&priv_key);
ret = mbedtls_pk_parse_key(
&priv_key,
key,
size,
NULL ,
0
);
However, the extracted value from TEE_GetObjectBufferAttribute does not have the headers and footpage:
"-----BEGIN EC PRIVATE KEY-----"
"-----END EC PRIVATE KEY-----"
and is only a binary array (not a string). I am currently getting the following error code: "-15616: PK - Invalid key tag or value".
Is there any way to create a mbedtls_pk_context with only the binary value of my private key?
The parsing functions in Mbed TLS's pk.h expect DER or PEM input. If you can find ready-made code to export a key as DER (or PEM) from OPTEE, that'll be easier (but possibly marginally less efficient). On the other hand, it's easier to do the import manually than to write a DER export function.
You need to call mbedtls_pk_setup() to declare that the context will contain an ECC key, then build the ECC key directly using the interface in ecp.h. Convert the curve designation from the TEE encoding to the Mbed TLS encoding, and calculate the public key from the private value. (Alternatively, you could export TEE_ATTR_ECC_PUBLIC_VALUE and set ec->Q, but that's more work.)
mbedtls_ecp_grp_id grp_id = …; // you need to convert this from the `TEE_ATTR_ECC_CURVE`
mbedtls_pk_context pk;
mbedtls_ecp_keypair *ec = malloc(sizeof(mbedtls_ecp_keypair));
mbedtls_pk_init(&pk);
mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECDSA));
mbedtls_ecp_keypair_init(ec);
mbedtls_ecp_group_load(&ec->grp, grp_id);
mbedtls_mpi_read_binary(&ec->d, buffer, bufferlen);
mbedtls_ecp_check_privkey(&ec->grp, &ec->d);
mbedtls_ecp_mul(&ec->grp, &ec->Q, &ec->d, &ec->grp.G, mbedtls_ctr_drbg_random, &ctr_drbg);
pk->pk_ctx = ec;
Completely untested. Error checking omitted. ctr_drbg is a CTR_DRBG instance, used for blinding during the calculation of the public key.
To add to the accepted answer here is the code to import Q if there are X and Y available as buffers. And I guess those are available since in order to create an ECDSA key in OPTEE using GlobalPlatform crypto API all 4 attributes (TEE_ATTR_xxx) are required (d, Q(X,Y) and the curve id)
rc = mbedtls_mpi_read_binary(&ec->Q.X, buffer_x, buffer_x_size);
rc = mbedtls_mpi_read_binary(&ec->Q.Y, buffer_y, buffer_y_size);
rc = mbedtls_mpi_lset(&ec->Q.Z, 1);
rc = mbedtls_ecp_check_pubkey(&ec->grp, &ec->Q);
I get a encrypted base64 string from python. The format is AES 256 CBC. But when I try to decrypt using iOS Swift it return decrypted string as nil.
# coding=utf-8
import base64
from random import choice
from string import letters
try:
from Crypto import Random
from Crypto.Cipher import AES
except ImportError:
import crypto
import sys
sys.modules['Crypto'] = crypto
from crypto.Cipher import AES
from crypto import Random
class AESCipher(object):
def __init__(self, key):
self.bs = 32
self.key = key
def encrypt(self, raw):
_raw = raw
raw = self._pad(raw)
print raw, ';'
print _raw, ';'
iv = "".join([choice(letters[:26]) for i in xrange(16)])
print " iv :", iv
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw))
def decrypt(self, enc):
enc = base64.b64decode(enc)
iv = enc[:AES.block_size]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
def _pad(self, s):
a = (self.bs - len(s) % self.bs)
b = chr(self.bs - len(s) % self.bs)
return s + a * b
#staticmethod
def _unpad(s):
return s[:-ord(s[len(s) - 1:])]
def encrypt(k, t):
o = AESCipher(k)
return o.encrypt(t)
def decrypt(k, t):
o = AESCipher(k)
return o.decrypt(t)
def main():
k = "qwertyuiopasdfghjklzxcvbnmqwerty"
s1 = "Hello World!"
d2 = encrypt(k, s1)
print " Password :", k
print "Encrypted :", d2
print " Plain :", decrypt(k, d2)
if __name__ == '__main__':
main()
iOS
Here I use AES256CBC Lib https://github.com/SwiftyBeaver/AES256CBC
let decrypted = AES256CBC.decryptString("Ymdqc3ZqdmZ1cXdsZG1sZenhgr4Xt0+ceARYRh1n40QkNDV/dyKbQjYLcbiXBBeO", password: "qwertyuiopasdfghjklzxcvbnmqwerty")
print("decrypted: \(String(describing: decrypted))") // here I get nil
when python run I get this Logs
iv : bgjsvjvfuqwldmle
Password : qwertyuiopasdfghjklzxcvbnmqwerty
Encrypted : Ymdqc3ZqdmZ1cXdsZG1sZenhgr4Xt0+ceARYRh1n40QkNDV/dyKbQjYLcbiXBBeO
Plain : Hello World!
I don't know why python and iOS not same in AES. Anyone solve this issue please put answer below. Thanks in advance.
I think you need to decode your base64 string first.
Maybe this will work (just googled it, I'm not a iOS dev, so I'm sorry to eventual errors)
let decodedData = NSData("Ymdqc3ZqdmZ1cXdsZG1sZenhgr4Xt0+ceARYRh1n40QkNDV/dyKbQjYLcbiXBBeO": base64String, options:NSDataBase64DecodingOptions.fromRaw(0)!)
let decodedString = NSString(data: decodedData, encoding: NSUTF8StringEncoding)
let decrypted = AES256CBC.decryptString(decodedString, password: "qwertyuiopasdfghjklzxcvbnmqwerty")
print("decrypted: \(String(describing: decrypted))")
It's also stated in the documentation
I'm not good at English
and my English is Grammar is wrong
wish for understanding
I am using ARRAY CLASS in OJDBC6.
Use it(ARRAY class) to send data to oracle database(procedure).
Data of number type and date type is very well in oracle.
Howerver data of varchar2 type is null in oracle (ARRAY)
I see diffrent solution (java path setup orai18n.jar file)
but it have error of java.lang.NoSuchMethodError: oracle.i18n.text.converter.CharacterConverterOGS.getInstance(I)Loracle/i18n/text/converter/CharacterConverter;
I don't found A solution to this problem
Please How to solve this problem ~~ ~~
I use JDK1.7,OJDBC6.jar
----------------------------------------------orclae code----------------------------------
CREATE OR REPLACE
TYPE XXXXXXXX_TYPE AS OBJECT(
nnnnnnn1 NUMBER
,nnnnnnn2 NUMBER
,nnnnnnn3 NUMBER
,vvvvvvv1 VARCHAR2(150)
,nnnnnnn4 NUMBER
,dddddddd1 DATE
,vvvvvvv2 VARCHAR2(250)
,nnnnnnn5 NUMBER
,dddddddd2 DATE
,nnnnnnn6 NUMBER
,dddddddd3 DATE
,nnnnnnn7 NUMBER
,vvvvvvv3 VARCHAR2(10)
,vvvvvvv4 VARCHAR2(30)
,vvvvvvv5 VARCHAR2(20)
,vvvvvvv6 VARCHAR2(80)
--XXXXXXXX_TYPE end
CREATE OR REPLACE
TYPE XXXXXXXXXXX_TBL AS TABLE OF XXXXXXXX_TYPE
-- XXXXXXXXXXX_TBL end
------------------------------------------java----------------------------------
public class Ex_mainJava {
public static void main(String[] args){
DBPoolCon db = DBPoolCon.getInstance();
String str = "{call xxx_xxx_xxxx_xxxx_result_pkg.XX_XX_result(?,?,?)}";
try {
Connection oracleConn = (OracleConnection) db.buildPoolConnection();
CallableStatement callStatement = oracleConn.prepareCall(str);
Object[][] x_ctr_tbl = new Object[1][16];
x_ctr_tbl[0][0] = 1;
x_ctr_tbl[0][1] = 2;
x_ctr_tbl[0][2] = 3;
x_ctr_tbl[0][3] = "ABC";
x_ctr_tbl[0][4] = 4;
x_ctr_tbl[0][5] = java.sql.Date.valueOf("2014-06-18");
x_ctr_tbl[0][6] = "DEF";
x_ctr_tbl[0][7] = 5;
x_ctr_tbl[0][8] = java.sql.Date.valueOf("2014-06-18");
x_ctr_tbl[0][9] = 6;
x_ctr_tbl[0][10] = java.sql.Date.valueOf("2014-06-18");
x_ctr_tbl[0][11] = 7;
x_ctr_tbl[0][12] = "HHHH";
x_ctr_tbl[0][13] = "KKKK";
x_ctr_tbl[0][14] = "JJJJ";
x_ctr_tbl[0][15] = "MMMM";
ArrayDescriptor oracleCollection2 = ArrayDescriptor.createDescriptor("XXXXXXXXXXX_TBL ".toUpperCase(),oracleConn);
ARRAY oraArry2 = new ARRAY(oracleCollection2, oracleConn,x_ctr_tbl);
System.out.println(oraArry2.dump());
callStatement.registerOutParameter(1, java.sql.Types.VARCHAR);
callStatement.registerOutParameter(2, java.sql.Types.INTEGER);
callStatement.setArray(3,oraArry2);
callStatement.execute();
String s =callStatement.getString(1);
int i = callStatement.getInt(2);
System.out.println("error:"+s);
System.out.println("code:"+i);
callStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
---------console-----------------------------------
System.out.println(oraArry2.dump());
nnnnnnn1 1
,nnnnnnn2 2
,nnnnnnn3 3
vvvvvvv1 ??? <---problem
nnnnnnn4 4
dddddddd1 2014-06-18 00:00:00.0
vvvvvvv2 ??? <---problem
nnnnnnn5 5
dddddddd2 2014-06-18 00:00:00.0
nnnnnnn6 6
dddddddd3 2014-06-18 00:00:00.0
nnnnnnn7 7
vvvvvvv3 ??? <---problem
vvvvvvv4 ??? <---problem
vvvvvvv5 ??? <---problem
vvvvvvv6 ??? <---problem
EXAMPLE CODE SOURCE
please help me to problem of ??? (problem)
Thank you.
you read my source for my problem
I have successfully encrypted data in BlackBerry in AES format. In order to verify my result, I am trying to implement decryption in BlackBerry using the following method:
private static byte[] decrypt( byte[] keyData, byte[] ciphertext )throws CryptoException, IOException
{
// First, create the AESKey again.
AESKey key = new AESKey( keyData );
// Now, create the decryptor engine.
AESDecryptorEngine engine = new AESDecryptorEngine( key );
// Since we cannot guarantee that the data will be of an equal block length
// we want to use a padding engine (PKCS5 in this case).
PKCS5UnformatterEngine uengine = new PKCS5UnformatterEngine( engine );
// Create the BlockDecryptor to hide the decryption details away.
ByteArrayInputStream input = new ByteArrayInputStream( ciphertext );
BlockDecryptor decryptor = new BlockDecryptor( uengine, input );
// Now, read in the data. Remember that the last 20 bytes represent
// the SHA1 hash of the decrypted data.
byte[] temp = new byte[ 100 ];
DataBuffer buffer = new DataBuffer();
for( ;; ) {
int bytesRead = decryptor.read( temp );
buffer.write( temp, 0, bytesRead );
if( bytesRead < 100 ) {
// We ran out of data.
break;
}
}
byte[] plaintextAndHash = buffer.getArray();
int plaintextLength = plaintextAndHash.length - SHA1Digest.DIGEST_LENGTH;
byte[] plaintext = new byte[ plaintextLength ];
byte[] hash = new byte[ SHA1Digest.DIGEST_LENGTH ];
System.arraycopy( plaintextAndHash, 0, plaintext, 0, plaintextLength );
System.arraycopy( plaintextAndHash, plaintextLength, hash, 0,
SHA1Digest.DIGEST_LENGTH );
// Now, hash the plaintext and compare against the hash
// that we found in the decrypted data.
SHA1Digest digest = new SHA1Digest();
digest.update( plaintext );
byte[] hash2 = digest.getDigest();
if( !Arrays.equals( hash, hash2 )) {
throw new RuntimeException();
}
return plaintext;
}
I get an exception thrown "BadPaddingException" at the following line
int bytesRead = decryptor.read( temp );
Can anybody please help.
I think the problem might be in this block:
for( ;; ) {
int bytesRead = decryptor.read( temp );
buffer.write( temp, 0, bytesRead );
if( bytesRead < 100 ) {
// We ran out of data.
break;
}
}
When read returns -1, you are also writing it to the buffer. And the exit condition is also wrong. Compare that to the block in CryptoDemo sample project:
for( ;; ) {
int bytesRead = decryptor.read( temp );
if( bytesRead <= 0 )
{
// We have run out of information to read, bail out of loop
break;
}
db.write(temp, 0, bytesRead);
}
Also there are a few points you should be careful about, even if they are not causing the error:
AESDecryptorEngine engine = new AESDecryptorEngine( key );
If you read the docs for this constructor, it says:
"Creates an instance of the AESEncryptorEngine class given the AES key
with a default block length of 16 bytes."
But in the previous line, when you create the key, you are doing this:
AESKey key = new AESKey( keyData );
Which according to the docs, it "Creates the longest key possible from existing data.", BUT only "the first 128 bits of the array are used". So it does not matter what length your keyData has, you will always be using a 128 bit key length, which is the shortest of the 3 available sizes (128, 192, 256).
Instead, you could explicitly select the algorithm block key length. For instance, to use AES-256:
AESKey key = new AESKey(keyData, 0, 256); //key length in BITS
AESDecryptorEngine engine = new AESDecryptorEngine(key, 32); //key lenth IN BYTES
Finally, even if you get this working, you should be aware that directly deriving the key from the password (which might be of an arbitrary size) is not secure. You could use PKCS5KDF2PseudoRandomSource to derive an stronger key from the key material (password), instead of just using PKCS5 for padding.
Your encrypted data should be correctly padded to the block size (16 bytes).
Try to decrypt the data without padding, and see if tail bytes correspond to PKCS#5 padding (for instance, if it was needed 5 bytes of padding, it should be appended with 0x05 0x05 0x05 0x05 0x05 bytes).
The problem is that any data with the correct block size will decrypt. The issue with that is that it will likely decrypt to random looking garbage. Random looking garbage is not often compatible with the PKCS#7 padding scheme, hence the exception.
I say problem because this exception may be thrown if the key data is invalid, if the wrong padding or block mode was used or simply if the input data was garbled during the process. The best way to debug this is to make 100% sure that the algorithms match, and that the binary input parameters (including default ones by the API) match precisely on both sides.