# Smart Card Shell

- - Home
- - GPError
  - GPSystem
  - ByteString
  - ByteBuffer
  - TLV
  - TLVList
  - Card
  - Atr
  - Key
  - Crypto
  - Application
  - GPApplication
  - GPSecDomain
- - ASN1
  - CardFile
  - IsoSecureChannel
  - ApplFactory
  - GPXML
  - JsScript
  - CardSim
- - X509
  - CRL
  - KeyStore
  - Signed CMS
  - Enveloped CMS
  - CMS Generator
  - XMLSignature
  - SSS
  - OCSPQuery
  - LDAP
  - SOAP
  - URLConnection
- - PKCS11Provider
  - PKCS11Session
  - PKCS11Object
- - OutlineNode
  - Dialog
  - Task
- - Tools
  - Modules
- - OpenSCDP

# Crypto - Reference Documentation

Implements access to cryptographic services.

## Index of Methods

- Crypto() constructor
- encrypt()
- decrypt()
- sign()
- verify()
- deriveKey()
- digest()
- generateKeyPair()
- generateRandom()

## Constants

Type | Name | Description
--- | --- | ---
Number | RSA | RSA algorithm
Number | RSA_ISO9796_2 | RSA algorithm in ISO-9796-2 variant
Number | RSA_PKCS1 | RSA Encryption with PKCS#1 V1.5 padding
Number | RSA_OAEP | RSA Encryption with OAEP padding using SHA-1 and MGF1
Number | RSA_OAEP_SHA224 | RSA Encryption with OAEP padding using SHA-224 and MGF1
Number | RSA_OAEP_SHA256 | RSA Encryption with OAEP padding using SHA-256 and MGF1
Number | RSA_OAEP_SHA384 | RSA Encryption with OAEP padding using SHA-384 and MGF1
Number | RSA_OAEP_SHA512 | RSA Encryption with OAEP padding using SHA-512 and MGF1
Number | RSA_SHA1 | SHA-1 with RSA signature algorithm and PKCS#1 V1.5 encoding
Number | RSA_SHA224 | SHA-224 with RSA signature algorithm and PKCS#1 V1.5 encoding
Number | RSA_SHA256 | SHA-256 with RSA signature algorithm and PKCS#1 V1.5 encoding
Number | RSA_SHA384 | SHA-384 with RSA signature algorithm and PKCS#1 V1.5 encoding
Number | RSA_SHA512 | SHA-512 with RSA signature algorithm and PKCS#1 V1.5 encoding
Number | RSA_PSS_SHA1 | SHA-1 with RSA signature algorithm and PKCS#1 V1.5 encoding
Number | RSA_PSS_SHA224 | SHA-224 with RSA signature algorithm and PSS encoding
Number | RSA_PSS_SHA256 | SHA-256 with RSA signature algorithm and PSS encoding
Number | RSA_PSS_SHA384 | SHA-384 with RSA signature algorithm and PSS encoding
Number | RSA_PSS_SHA512 | SHA-512 with RSA signature algorithm and PSS encoding
Number | EC | Elliptic curve key operation
Number | ECDSA | Elliptic curve digital signature algorithm without hash
Number | ECDSA_SHA1 | Elliptic curve digital signature algorithm using SHA-1
Number | ECDSA_SHA224 | Elliptic curve digital signature algorithm using SHA-224
Number | ECDSA_SHA256 | Elliptic curve digital signature algorithm using SHA-256
Number | ECDSA_SHA384 | Elliptic curve digital signature algorithm using SHA-384
Number | ECDSA_SHA512 | Elliptic curve digital signature algorithm using SHA-512
Number | ECDH | Elliptic curve Diffie-hellman algorithm
Number | ECDHC | Elliptic curve Diffie-hellman algorithm with cofactor
Number | ECDHP | Elliptic curve Diffie-hellman algorithm returning x and y coordinate of shared point
Number | EC_MULTIPLY_ADD | Elliptic curve point multiplication and addition
Number | EC_MULTIPLY_SUB | Elliptic curve point multiplication and substraction
Number | ECELGAMAL | ElGamal Decryption
Number | DES_CBC | Cipher Block Chaining encryption using DES
Number | DES_ECB | Electronic Cook Book encryption using DES
Number | AES_CBC | Cipher Block Chaining encryption using AES
Number | AES_ECB | Electronic Cook Book encryption using AES
Number | AES_CTR | Segmented Integer Counter (CTR) encryption using AES
Number | AES_CMAC | Message Authentication Code (MAC) acccording to NIST Special Publication 800-38B
Number | MD5 | MD5 message digest algorithm
Number | SHA_1 | SHA-1 message digest algorithm
Number | SHA_224 | SHA-224 message digest algorithm
Number | SHA_256 | SHA-256 message digest algorithm
Number | SHA_384 | SHA-384 message digest algorithm
Number | SHA_512 | SHA-512 message digest algorithm
Number | DES_MAC | Message authentication code using 3DES for each block
Number | DES_MAC_EMV | Message authentication code using DES for each block and 3DES for final block (Retail MAC)
Number | DES_CBC_LP | Variant of DES_CBC encryption used for wrap operations (Length || Key || ISOPadding)
Number | DES_CBC_P | Variant of DES_CBC encryption used for wrap operations (Key || ISOPadding)
Number | DES_ECB_LP | Variant of DES_ECB encryption used for wrap operations (Length || Key || ISOPadding)
Number | DES_ECB_P | Variant of DES_ECB encryption used for wrap operations (Key || ISOPadding)
Number | ISO9797_METHOD_1 | Padding method according to ISO 9797 with 8 byte block size
Number | ISO9797_METHOD_2 | Padding method according to ISO 9797 with 8 byte block size
Number | ISO9797_METHOD_1_16 | Padding method according to ISO 9797 with 16 byte block size
Number | ISO9797_METHOD_2_16 | Padding method according to ISO 9797 with 16 byte block size
Number | DES | Constant to denote a single length (56 bit) DES key in generateKey()
Number | DES2 | Constant to denote a double length (112 bit) DES key in generateKey()
Number | DES3 | Constant to denote a double length (168 bit) DES key in generateKey()
Number | HMAC_SHA1 | Constant to denote a Hashmac using SHA-1
Number | HMAC_SHA256 | Constant to denote a Hashmac using SHA-256
Number | HMAC_SHA384 | Constant to denote a Hashmac using SHA-256
Number | HMAC_SHAMD5 | Constant to denote a Hashmac using MD5

## Constructor

### Prototype

Crypto()

Crypto(String provider)

Crypto(String provider, String password)

### Description

Create a crypto object and bind it to the given cryptographic service provider. If no provider is defined, then the default provider "BC" will be used.

### Arguments

Type | Name | Description
--- | --- | ---
`String` | provider | Name of cryptographic service provider (JCE Provider)
`String` | password | Password to activated provider

### Exceptions

Name | Value | Description
--- | --- | ---
GPError | GPError.INVALID_ARGUMENTS | Too many arguments given
GPError | GPError.INVALID_TYPE | On or more arguments are not of the expected type

### Example

    crypto = new Crypto();
    assert(crypto != null);

    crypto = new Crypto("BC");
    assert(crypto != null);

## encrypt()

### Prototype

ByteString encrypt(Key key, Number mech, ByteString data)

ByteString encrypt(Key key, Number mech, ByteString data, ByteString iv)

### Description

Encrypt the plain data using the algorithm defined by mech and the specified key.

The Crypto.RSA mechanism performs a plain RSA encrypt operation with no encoding format.

The Crypto.RSA_ISO9796_2 mechanism performs a plain RSA encrypt operation with no encoding format but according to ISO 9697-2. The result is less than half of the modulus.

The Crypto.PKCS1 mechanism performs a plain RSA encrypt operation with PKCS1 V1.5 encoding format.

The Crypto.OAEP_XXX mechanism performs a plain RSA encrypt operation with PKCS1 V2.1 OEAP encoding format using the selected message digest algorithm.

If the algorithm requires an initialisation vector, then the additional argument iv must be specified (DES_CBC, AES_CBC or AES_CTR).

### Arguments

Type | Name | Description
--- | --- | ---
`Key` | key | Key object representing the key
`Key` | mech | Algorithm to be used to decryption. Must be one of Crypto.DES_CBC, Crypto.DES_ECB, Crypto.AES_CBC, Crypto.AES_ECB, Crypto.AES_ECB or Crypto.RSA.
`ByteString` | data | The data to be encrypted

### Return

`ByteString` | Returns the plain text value

### Exceptions

Name | Value | Description
--- | --- | ---
GPError | GPError.ARGUMENTS_MISSING | Too few arguments in call
GPError | GPError.INVALID_ARGUMENTS | Too many arguments in call
GPError | GPError.INVALID_TYPE | Type of argument is invalid for method invocation
GPError | GPError.INVALID_MECH | The mechanism is invalid

### Example

    // Instantiate crypto service
    var crypto = new Crypto();

    // Define 3 different single DES key values
    var key1 = new ByteString("7CA110454A1A6E57", HEX);
    var key2 = new ByteString("0131D9619DC1376E", HEX);
    var key3 = new ByteString("9DC1376E0131D961", HEX);

    var plain = new ByteString("01A1D6D039776742", HEX);
    var cipher;
    var result;

    // Create three single DES keys, a double DES key and a triple DES key
    var deskey1 = new Key();
    deskey1.setComponent(Key.DES, key1);

    var deskey2 = new Key();
    deskey2.setComponent(Key.DES, key2);

    var deskey3 = new Key();
    deskey3.setComponent(Key.DES, key3);

    var des2key = new Key();
    des2key.setComponent(Key.DES, key1.concat(key2));

    var des3key = new Key();
    des3key.setComponent(Key.DES, key1.concat(key2).concat(key3));

    // Single DES ECB encrypt
    cipher = new ByteString("690F5B0D9A26939B", HEX);

    result = crypto.encrypt(deskey1, Crypto.DES_ECB, plain);
    assert(result.equals(cipher));

    // Single DES ECB decrypt
    result = crypto.decrypt(deskey1, Crypto.DES_ECB, cipher);
    assert(result.equals(plain));

    // Double DES ECB encrypt
    cipher = plain;
    cipher = crypto.encrypt(deskey1, Crypto.DES_ECB, cipher);
    cipher = crypto.decrypt(deskey2, Crypto.DES_ECB, cipher);
    cipher = crypto.encrypt(deskey1, Crypto.DES_ECB, cipher);

    result = crypto.encrypt(des2key, Crypto.DES_ECB, plain);
    assert(result.equals(cipher));

    // Double DES ECB decrypt
    result = crypto.decrypt(des2key, Crypto.DES_ECB, cipher);
    assert(result.equals(plain));

    // Triple DES ECB encrypt
    cipher = plain;
    cipher = crypto.encrypt(deskey1, Crypto.DES_ECB, cipher);
    cipher = crypto.decrypt(deskey2, Crypto.DES_ECB, cipher);
    cipher = crypto.encrypt(deskey3, Crypto.DES_ECB, cipher);

    result = crypto.encrypt(des3key, Crypto.DES_ECB, plain);
    assert(result.equals(cipher));

    // Triple DES ECB decrypt
    result = crypto.decrypt(des3key, Crypto.DES_ECB, cipher);
    assert(result.equals(plain));

    // Single DES CBC encrypt
    var plain = new ByteString("01A1D6D0397767423977674201A1D6D0", HEX);
    var iv = new ByteString("59D9839733B8455D", HEX);
    var v;

    v = plain.bytes(0, 8);
    v = v.xor(iv);
    v = crypto.encrypt(deskey1, Crypto.DES_ECB, v);
    cipher = v;

    v = plain.bytes(8, 8);
    v = cipher.xor(v);
    v = crypto.encrypt(deskey1, Crypto.DES_ECB, v);
    cipher = cipher.concat(v);

    result = crypto.encrypt(deskey1, Crypto.DES_CBC, plain, iv);
    assert(result.equals(cipher));

    // Single DES CBC decrypt
    result = crypto.decrypt(deskey1, Crypto.DES_CBC, cipher, iv);
    assert(result.equals(plain));

    // Encrypt and decrypt with AES key

    var key = new Key();

    // Make key a 128 bit AES key
    key.setComponent(Key.AES, new ByteString("000102030405060708090a0b0c0d0e0f", HEX));
    var plain = new ByteString("00112233445566778899aabbccddeeff", HEX);
    var cipher = new ByteString("69c4e0d86a7b0430d8cdb78070b4c55a", HEX);

    var result = crypto.encrypt(key, Crypto.AES_ECB, plain);
    assert(cipher.equals(result));

    var result = crypto.decrypt(key, Crypto.AES_ECB, cipher);
    assert(plain.equals(result));

    // Make key a 192 bit AES key
    key.setComponent(Key.AES, new ByteString(
                "000102030405060708090a0b0c0d0e0f1011121314151617", HEX));
    var plain = new ByteString("00112233445566778899aabbccddeeff", HEX);
    var cipher = new ByteString("dda97ca4864cdfe06eaf70a0ec0d7191", HEX);
    var result = crypto.encrypt(key, Crypto.AES_ECB, plain);
    assert(cipher.equals(result));

    var result = crypto.decrypt(key, Crypto.AES_ECB, cipher);
    assert(plain.equals(result));

    // Make key a 256 bit AES key
    key.setComponent(Key.AES, new ByteString(
                "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", HEX));
    var plain = new ByteString("00112233445566778899aabbccddeeff", HEX);
    var cipher = new ByteString("8ea2b7ca516745bfeafc49904b496089", HEX);
    var result = crypto.encrypt(key, Crypto.AES_ECB, plain);
    assert(cipher.equals(result));

    var result = crypto.decrypt(key, Crypto.AES_ECB, cipher);
    assert(plain.equals(result));

    // AES CTR mode
    key.setComponent(Key.AES, new ByteString("2b7e151628aed2a6abf7158809cf4f3c", HEX));
    var plain = new ByteString("6bc1bee22e409f96e93d7e117393172a", HEX);
    var cipher = new ByteString("874d6191b620e3261bef6864990db6ce", HEX);
    var iv = new ByteString("F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF", HEX);

    var result = crypto.encrypt(key, Crypto.AES_CTR, plain, iv);
    assert(cipher.equals(result));

    var result = crypto.decrypt(key, Crypto.AES_CTR, cipher, iv);
    assert(plain.equals(result));

    // Decrypt and encrypt as basically the same in CTR mode
    var result = crypto.encrypt(key, Crypto.AES_CTR, cipher, iv);
    assert(plain.equals(result));

    // RSA encrypt with plain input block

    // Make RSA private key from modulus and private exponent

    var rsaprkey = new Key();
    rsaprkey.setType(Key.PRIVATE);

    rsaprkey.setComponent(Key.MODULUS, new ByteString(
                "b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9" +
                "900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", HEX));
    rsaprkey.setComponent(Key.EXPONENT, new ByteString(
                "9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae" +
                "79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", HEX));

    // Make RSA public key from modulus and public exponent

    var rsapukey = new Key();
    rsapukey.setType(Key.PUBLIC);
    rsapukey.setComponent(Key.MODULUS, new ByteString(
                "b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9"+
                "900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", HEX));
    rsapukey.setComponent(Key.EXPONENT, new ByteString("11", HEX));

    var inp = new ByteString(
                "2600000000000000000000000000000000000000000000000000000000000000" +
                "0000000000000000000000000000000000000000000000000000000000000000", HEX);
    assert(inp.length == 64);

    var cipher = crypto.encrypt(rsaprkey, Crypto.RSA, inp);

    print(cipher);

    var plain = crypto.decrypt(rsapukey, Crypto.RSA, cipher);

    print(plain);
    assert(plain.equals(inp));

    // RSA encrypt with OAEP padding

    var inp = new ByteString("Message", ASCII);

    var cipher = crypto.encrypt(rsapukey, Crypto.RSA_OAEP, inp);

    print(cipher);

    var plain = crypto.decrypt(rsaprkey, Crypto.RSA, cipher);

    print("Decrypted OAEP block:");
    print(plain);

    assert(plain.byteAt(0) == 0);

    var plain = crypto.decrypt(rsaprkey, Crypto.RSA_OAEP, cipher);
    assert(plain.equals(inp));

    //RSA encrypt with PKCS#1 V1.5 padding

    var inp = new ByteString("Message", ASCII);

    var cipher = crypto.encrypt(rsapukey, Crypto.RSA_PKCS1, inp);

    print(cipher);

    var plain = crypto.decrypt(rsaprkey, Crypto.RSA, cipher);

    print("Decrypted PKCS#1 V1.5 block:");
    print(plain);

    assert(plain.byteAt(0) == 0);
    assert(plain.byteAt(1) == 2);

    var plain = crypto.decrypt(rsaprkey, Crypto.RSA_PKCS1, cipher);
    assert(plain.equals(inp));

    // Encrypt and decrypt with RSA primitive using ISO 9796-2 (DINSIG) variant that
    // ensures that the numeric value of the output message is less than half of the
    // modulus
    var inp = new ByteString(
                "260000000000000000000000000000000000000000000000000000000000000" +
                "000000000000000000000000000000000000000000000000000000000000000BC", HEX);
    assert(inp.length == 64);

    var cipher = crypto.encrypt(rsaprkey, Crypto.RSA_ISO9796_2, inp);

    print(cipher);

    var plain = crypto.decrypt(rsapukey, Crypto.RSA_ISO9796_2, cipher);
    assert(plain.equals(inp));

    // Make RSA private key from CRT components stored in key profile

    var rsaprkey = new Key("profiles/kp_rsa_private_crt.xml");

    // Make RSA public key from modulus and public exponent stored in key profile

    var rsapukey = new Key("profiles/kp_rsa_public.xml");

    // rsaprkey.setComponent(Key.EXPONENT, rsapukey.getComponent(Key.EXPONENT));

    var inp = new ByteString(
                "2600000000000000000000000000000000000000000000000000000000000000" +
                "0000000000000000000000000000000000000000000000000000000000000000", HEX);
    assert(inp.length == 64);

    var cipher = crypto.encrypt(rsaprkey, Crypto.RSA, inp);

    print(cipher);

    var plain = crypto.decrypt(rsapukey, Crypto.RSA, cipher);

    print(plain);
    assert(plain.equals(inp));

## decrypt()

### Prototype

ByteString decrypt(Key key, Number mech, ByteString data)

ByteString decrypt(Key key, Number mech, ByteString data, ByteString iv)

### Description

Decrypt the cipher in data using the algorithm defined by mech and the specified key. If the algorithm requires an initialisation vector, then the additional argument iv must be specified (DES_CBC, AES_CBC or AES_CTR).

The Crypto.RSA mechanism performs a plain RSA decrypt operation with no encoding format.

The Crypto.RSA_ISO9796_2 mechanism performs a plain RSA decrypt operation with no encoding format but according to ISO 9697-2.

The Crypto.PKCS1 mechanism performs a RSA decrypt operation with PKCS1 V1.5 encoding format.

The Crypto.OAEP_XXX mechanism performs a RSA decrypt operation with PKCS1 V2.1 OEAP encoding format using the selected message digest algorithm and MGF1.

This method can also be used to perform an ECDH or an ECDHC with cofactor primitive using a private EC key. The method treats the data as x and y coordinate of the EC public key from the sending party.

The Crypto.ECDH method return as result the x coordinate of the multiplication of the private key value d with the public point Q (result = xof(d * q))

The Crypto.ECDHC method returns as result the x coordinate of the multiplication of the private key value d with the cofactor h and the public point Q (result = xof(d * h * q)). The cofactor is a parameter of the curve.

The Crypto.ECDHP method returns as result the concatenation of the x and y coordinate of the multiplication of the private key value d with the public point Q (result = d * h * q). This method is a non-standard variant, only available with the default BouncyCastle crypto provider.

The ECDH decryption is a basic building block for cipher operations based on ECC. The result of the decrypt operation is a common secret, which can be either used directly as secret key or used as input to a key derivation process.

The Crypto.ECELGAMAL mechanism performs an ElGamal decrypt operation. The cryptogram is an ASN1 sequence containing the EC Points for blinding and cipher. Each point is encoded as public key sequence.

### Arguments

Type | Name | Description
--- | --- | ---
`Key` | key | Key object representing the key
`Key` | mech | Algorithm to be used to decryption. Must be one of Crypto.DES_CBC, Crypto.DES_ECB, Crypto.AES_CBC, Crypto.AES_ECB, Crypto.AES_CTR, Crypto.RSA, Crypto.ECDH, Crypto.ECDHC, Crypto.ECDHP or Crypto.ECELGAMAL.
`ByteString` | data | The cryptogram

### Return

`ByteString` | Returns the plain text value

### Exceptions

Name | Value | Description
--- | --- | ---
GPError | GPError.ARGUMENTS_MISSING | Too few arguments in call
GPError | GPError.INVALID_ARGUMENTS | Too many arguments in call
GPError | GPError.INVALID_TYPE | Type of argument is invalid for method invocation
GPError | GPError.INVALID_DATA | The data or initial vector provided is invalid
GPError | GPError.INVALID_MECH | The mechanism is invalid

### Example

    // See encrypt() for a complete example using DES and RSA

    // ECDH Generating a shared secret between Bob and Alice to exchange protected messages

    var pubKeyBob = new Key();
    pubKeyBob.setType(Key.PUBLIC);
    pubKeyBob.setComponent(Key.ECC_CURVE_OID, new ByteString("1.2.840.10045.3.1.1", OID));

    var priKeyBob = new Key();
    priKeyBob.setType(Key.PRIVATE);
    priKeyBob.setComponent(Key.ECC_CURVE_OID, new ByteString("1.2.840.10045.3.1.1", OID));
    crypto.generateKeyPair(Crypto.EC, pubKeyBob, priKeyBob);

    var pubKeyAlice = new Key();
    pubKeyAlice.setType(Key.PUBLIC);
    pubKeyAlice.setComponent(Key.ECC_CURVE_OID,
                                        new ByteString("1.2.840.10045.3.1.1", OID));

    var priKeyAlice = new Key();
    priKeyAlice.setType(Key.PRIVATE);
    priKeyAlice.setComponent(Key.ECC_CURVE_OID,
                                        new ByteString("1.2.840.10045.3.1.1", OID));
    crypto.generateKeyPair(Crypto.EC, pubKeyAlice, priKeyAlice);

    var inputBob = pubKeyBob.getComponent(Key.ECC_QX).concat(
                                        pubKeyBob.getComponent(Key.ECC_QY));
    var inputAlice = pubKeyAlice.getComponent(Key.ECC_QX).concat(
                                        pubKeyAlice.getComponent(Key.ECC_QY));

    var secretAlice = crypto.decrypt(priKeyAlice, Crypto.ECDH, inputBob);
    print(secretAlice);

    var secretBob = crypto.decrypt(priKeyBob, Crypto.ECDH, inputAlice);
    print(secretBob);

    assert(secretBob.equals(secretAlice));

    var secretAlice = crypto.decrypt(priKeyAlice, Crypto.ECDHC, inputBob);
    print(secretAlice);

    var secretBob = crypto.decrypt(priKeyBob, Crypto.ECDHC, inputAlice);
    print(secretBob);

    assert(secretBob.equals(secretAlice));

    var secretAlice = crypto.decrypt(priKeyAlice, Crypto.ECDHP, inputBob);
    print(secretAlice);

    var secretBob = crypto.decrypt(priKeyBob, Crypto.ECDHP, inputAlice);
    print(secretBob);

    assert(secretBob.equals(secretAlice));

    // ElGamal decryption

    // Create dummy EC Points representing the ELGamal ciphertext pair of blinding and cipher

    var blindingPoint = new Key();
    blindingPoint.setType(Key.PUBLIC);
    blindingPoint.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP320r1", OID));

    var cipherPoint = new Key();
    cipherPoint.setType(Key.PUBLIC);
    cipherPoint.setComponent(Key.ECC_CURVE_OID, new ByteString("brainpoolP320r1", OID));

    var priKey = new Key();
    priKey.setType(Key.PRIVATE);

    var crypto = new Crypto();
    crypto.generateKeyPair(Crypto.EC, blindingPoint, priKey);
    crypto.generateKeyPair(Crypto.EC, cipherPoint, priKey);

    // Encode ciphertext pair

    var blinding = new ByteString("04", HEX);
    blinding = blinding.concat(blindingPoint.getComponent(Key.ECC_QX));
    blinding = blinding.concat(blindingPoint.getComponent(Key.ECC_QY));

    cipher = new ByteString("04", HEX);
    cipher = cipher.concat(cipherPoint.getComponent(Key.ECC_QX));
    cipher = cipher.concat(cipherPoint.getComponent(Key.ECC_QY));

    var seq = new ASN1(ASN1.SEQUENCE);

    var pubSeq = new ASN1(0x7F49);
    pubSeq.add(new ASN1(0x06, new ByteString("brainpoolP320r1", OID)));
    pubSeq.add(new ASN1(0x86, blinding));
    seq.add(pubSeq);

    var pubSeq = new ASN1(0x7F49);
    pubSeq.add(new ASN1(0x06, new ByteString("brainpoolP320r1", OID)));
    pubSeq.add(new ASN1(0x86, cipher));
    seq.add(pubSeq);

    // ElGamal decryption

    var c = new Crypto();
    var resp = c.decrypt(priKey, Crypto.ECELGAMAL, seq.getBytes());

    print(new ASN1(resp));

## sign()

### Prototype

ByteString sign(Key key, Number mech, ByteString data)

ByteString sign(Key key, Number mech, ByteString data, ByteString iv)

### Description

Sign the data provided using the mechanism and key specified. If the algorithms requires an initialisation vector, then it can be provided in the iv argument.

When the Crypto.RSA argument is supplied, then RSA with SHA-1 and PKCS#1 V1.5 encoding is used as signature algorithm. Crypto.RSA has the same effect as Crypto.RSA_SHA1.

When the Crypto.ECDSA argument is supplied, then ECDSA without a hash is used, i.e. the hash value must be provided as input.

A signature created using ECDSA is encoded in an ASN1 SEQUENCE object containing an INTEGER object r and s. See RFC3279 for details.

A method to convert a TLV encoded ECDSA signature into a binary concatenation of the x and y coordinate is provided in the tools/eccutils.js script.

### Arguments

Type | Name | Description
--- | --- | ---
`Key` | key | Key reference object to be used for signature generation
`Number` | mech | Signature algorithm to be used. Must be one of Crypto.DES_MAC, Crypto.DES_MAC_EMV, Crypto.AES_MAC, Crypto.AES_CMAC, Crypto.RSA* or Crypto.ECDSA*.
`ByteString` | data | Input data for signature computation
`ByteString` | iv | Initialisation vector for symmetric algorithm

### Return

`ByteString` | Signature value

### Exceptions

Name | Value | Description
--- | --- | ---
GPError | GPError.ARGUMENTS_MISSING | Too few arguments in call
GPError | GPError.INVALID_ARGUMENTS | Too many arguments in call
GPError | GPError.INVALID_TYPE | Type of argument is invalid for method invocation
GPError | GPError.INVALID_MECH | The mechanism is invalid

### Example

    // Instantiate crypto service
    var crypto = new Crypto();

    // Define 3 different single DES key values
    var key1 = new ByteString("7CA110454A1A6E57", HEX);
    var key2 = new ByteString("0131D9619DC1376E", HEX);
    var key3 = new ByteString("9DC1376E0131D961", HEX);

    var plain = new ByteString("Hello World !!!!", ASCII);
    var cipher;
    var result;

    // Create three single DES keys, a double DES key and a triple DES key
    var deskey1 = new Key();
    deskey1.setComponent(Key.DES, key1);

    var deskey2 = new Key();
    deskey2.setComponent(Key.DES, key2);

    var deskey3 = new Key();
    deskey3.setComponent(Key.DES, key3);

    var des2key = new Key();
    des2key.setComponent(Key.DES, key1.concat(key2));

    var des3key = new Key();
    des3key.setComponent(Key.DES, key1.concat(key2).concat(key3));

    // Triple DES MAC
    cipher = crypto.encrypt(des3key, Crypto.DES_ECB, plain.bytes(0, 8));
    cipher = cipher.xor(plain.bytes(8, 8));
    cipher = crypto.encrypt(des3key, Crypto.DES_ECB, cipher);

    result = crypto.sign(des3key, Crypto.DES_MAC, plain);
    assert(result.equals(cipher));

    // Triple DES MAC according to EMV (aka Retail MAC)
    cipher = crypto.encrypt(deskey1, Crypto.DES_ECB, plain.bytes(0, 8));
    cipher = cipher.xor(plain.bytes(8, 8));
    cipher = crypto.encrypt(deskey1, Crypto.DES_ECB, cipher);
    cipher = crypto.decrypt(deskey2, Crypto.DES_ECB, cipher);
    cipher = crypto.encrypt(deskey1, Crypto.DES_ECB, cipher);

    result = crypto.sign(des2key, Crypto.DES_MAC_EMV, plain);
    assert(result.equals(cipher));

    // AES MAC
    // Make key a 128 bit AES key
    var key = new Key();
    key.setComponent(Key.AES, new ByteString("000102030405060708090a0b0c0d0e0f", HEX));
    var plain = new ByteString("01234567890123456789012345678901", ASCII);
    var cipher = crypto.encrypt(key, Crypto.AES_ECB, plain.bytes(0, 16));
    cipher = cipher.xor(plain.bytes(16, 16));
    var cipher = crypto.encrypt(key, Crypto.AES_ECB, cipher);

    result = crypto.sign(key, Crypto.AES_MAC, plain);
    assert(result.equals(cipher));

    //AES CMAC
    //Make key a 128 bit AES key
    var key = new Key();
    key.setComponent(Key.AES, new ByteString("2b7e151628aed2a6abf7158809cf4f3c", HEX));
    var plain = new ByteString("6bc1bee22e409f96e93d7e117393172aae2d8a571" +
                               "e03ac9c9eb76fac45af8e5130c81c46a35ce411", HEX);
    var mac = crypto.sign(key, Crypto.AES_CMAC, plain);
    var ref = new ByteString("dfa66747de9ae63030ca32611497c827", HEX);
    assert(ref.equals(mac));

    // RSA with SHA-1
    var rsaprkey = new Key("profiles/kp_rsa_private_crt.xml");
    var rsapukey = new Key("profiles/kp_rsa_public.xml");

    var message = new ByteString("Hello World !", ASCII);

    var signature = crypto.sign(rsaprkey, Crypto.RSA, message);

    print("Plain PKCS#1 V1.5 = " + crypto.decrypt(rsapukey, Crypto.RSA, signature));
    assert(crypto.verify(rsapukey, Crypto.RSA, message, signature));

    // RSA with SHA-224

    var signature = crypto.sign(rsaprkey, Crypto.RSA_SHA224, message);

    print("Plain PKCS#1 V1.5 = " + crypto.decrypt(rsapukey, Crypto.RSA, signature));
    assert(crypto.verify(rsapukey, Crypto.RSA_SHA224, message, signature));

    // RSA with SHA-256

    var signature = crypto.sign(rsaprkey, Crypto.RSA_SHA256, message);

    print("Plain PKCS#1 V1.5 = " + crypto.decrypt(rsapukey, Crypto.RSA, signature));
    assert(crypto.verify(rsapukey, Crypto.RSA_SHA256, message, signature));

    //RSA with SHA-1 and PSS

    var signature = crypto.sign(rsaprkey, Crypto.RSA_PSS_SHA1, message);

    print("Plain PSS = " + crypto.decrypt(rsapukey, Crypto.RSA, signature));
    assert(crypto.verify(rsapukey, Crypto.RSA_PSS_SHA1, message, signature));

    //Create empty public key object and set size
    var rsapukey = new Key();
    rsapukey.setType(Key.PUBLIC);
    rsapukey.setSize(1024);

    // Create empty private key object and set size
    var rsaprkey = new Key();
    rsaprkey.setType(Key.PRIVATE);

    // Generate key pair
    crypto.generateKeyPair(Crypto.RSA, rsapukey, rsaprkey);

    //RSA with SHA-256 and PSS

    var signature = crypto.sign(rsaprkey, Crypto.RSA_PSS_SHA256, message);

    print("Plain PSS = " + crypto.decrypt(rsapukey, Crypto.RSA, signature));
    assert(crypto.verify(rsapukey, Crypto.RSA_PSS_SHA256, message, signature));

    // ECDSA Fp with SHA-1
    var eccprkey = new Key("profiles/kp_ec_private.xml");
    var eccpukey = new Key("profiles/kp_ec_public.xml");

    var message = new ByteString("Hello World !", ASCII);

    var signature = crypto.sign(eccprkey, Crypto.ECDSA_SHA1, message);

    assert(crypto.verify(eccpukey, Crypto.ECDSA_SHA1, message, signature));

    /*
    // ECDSA F2m with SHA-1
    var eccprkey = new Key("profiles/kp_ec_f2m_private.xml");
    var eccpukey = new Key("profiles/kp_ec_f2m_public.xml");

    var message = new ByteString("Hello World !", ASCII);

    var signature = crypto.sign(eccprkey, Crypto.ECDSA_SHA1, message);

    assert(crypto.verify(eccpukey, Crypto.ECDSA_SHA1, message, signature));
    */
    // see Crypto.generateKeyPair for longer ECC keys

    // HMAC
    var msg = new ByteString("The quick brown fox jumps over the lazy dog", ASCII);
    var key = new Key();
    key.setComponent(Key.GENERIC, new ByteString("key", ASCII));

    assert(crypto.sign(key, Crypto.HMAC_SHA1, msg).equals(new ByteString("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9", HEX)));
    assert(crypto.sign(key, Crypto.HMAC_SHA256, msg).equals(new ByteString("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", HEX)));
    assert(crypto.sign(key, Crypto.HMAC_SHA384, msg).equals(new ByteString("D7F4727E2C0B39AE0F1E40CC96F60242D5B7801841CEA6FC592C5D3E1AE50700582A96CF35E1E554995FE4E03381C237", HEX)));
    assert(crypto.sign(key, Crypto.HMAC_MD5, msg).equals(new ByteString("80070713463e7749b90c2dc24911e275", HEX)));

## verify()

### Prototype

Boolean verify(Key key, Number mech, ByteString data, ByteString signature)

Boolean verify(Key key, Number mech, ByteString data, ByteString signature, ByteString iv)

### Description

Verify the signature applied to data with the mechanism and key specified

For ECDSA the signature must be TLV encoded as defined in RFC3279.

A method to convert a ECDSA signature encoded as binary concatenation of the x and y coordinate into the TLV format is provided in the tools/eccutils.js script.

### Arguments

Type | Name | Description
--- | --- | ---
`Key` | key | Key reference object to be used for signature verificaton
`Number` | mech | Verification algorithm to be used. Must be one of Crypto.DES_MAC, Crypto.DES_MAC_EMV, Crypto.AES_MAC, Crypto.RSA* or Crypto.ECDSA*.
`ByteString` | data | Input data for signature computation
`ByteString` | signature | Signature to be verified
`ByteString` | iv | Initialisation vector for symmetric algorithm

### Return

`Boolean` | True, if the signature was valid, false otherwise

### Exceptions

Name | Value | Description
--- | --- | ---
GPError | GPError.ARGUMENTS_MISSING | Too few arguments in call
GPError | GPError.INVALID_ARGUMENTS | Too many arguments in call
GPError | GPError.INVALID_TYPE | Type of argument is invalid for method invocation
GPError | GPError.INVALID_MECH | The mechanism is invalid

### Example

    // Instantiate crypto service
    var crypto = new Crypto();

    // Define 3 different single DES key values
    var key1 = new ByteString("7CA110454A1A6E57", HEX);
    var key2 = new ByteString("0131D9619DC1376E", HEX);
    var key3 = new ByteString("9DC1376E0131D961", HEX);

    var plain = new ByteString("Hello World !!!!", ASCII);
    var cipher;
    var result;

    // Create three single DES keys, a double DES key and a triple DES key
    var des1key = new Key();
    des1key.setComponent(Key.DES, key1);

    var des2key = new Key();
    des2key.setComponent(Key.DES, key1.concat(key2));

    var des3key = new Key();
    des3key.setComponent(Key.DES, key1.concat(key2).concat(key3));

    // Single DES MAC
    result = crypto.sign(des1key, Crypto.DES_MAC, plain);
    var ok = crypto.verify(des1key, Crypto.DES_MAC, plain, result);
    assert(ok);

    // Triple DES MAC
    result = crypto.sign(des3key, Crypto.DES_MAC, plain);
    var ok = crypto.verify(des3key, Crypto.DES_MAC, plain, result);
    assert(ok);

    // Triple DES MAC according to EMV (aka Retail MAC)
    result = crypto.sign(des2key, Crypto.DES_MAC_EMV, plain);
    var ok = crypto.verify(des2key, Crypto.DES_MAC_EMV, plain, result);
    assert(ok);

    // AES MAC
    // Make key a 128 bit AES key
    var key = new Key();
    key.setComponent(Key.AES, new ByteString("000102030405060708090a0b0c0d0e0f", HEX));
    var plain = new ByteString("01234567890123456789012345678901", ASCII);

    result = crypto.sign(key, Crypto.AES_MAC, plain);
    var ok = crypto.verify(key, Crypto.AES_MAC, plain, result);
    assert(ok);

    //AES CMAC
    //Make key a 128 bit AES key
    var key = new Key();
    key.setComponent(Key.AES, new ByteString("000102030405060708090a0b0c0d0e0f", HEX));
    var plain = new ByteString("01234567890123456789012345678901", ASCII);

    result = crypto.sign(key, Crypto.AES_CMAC, plain);
    var ok = crypto.verify(key, Crypto.AES_CMAC, plain, result);
    assert(ok);

    // RSA

    var cert = new X509("root.cer");
    var ncert = cert.getNative();

    var message = ncert.getTBSCertificate();
    var signature = ncert.getSignature();
    var key = cert.getPublicKey();

    assert(crypto.verify(key, Crypto.RSA, message, signature));

    // ECDSA

    var cert = new X509("ecdsacert.cer");
    var key = cert.getPublicKey();

    var message = new ByteString("Hello World", ASCII);

    // Be carefull if the most significant bit of r or s is 1. In that case you need
    // to add a 00 to prevent interpretation as negative integer
    var r = new ByteString("06CF31FCE556DC74F7B0B3061E47300CC11B3F5BFD01976A", HEX);
    var s = new ByteString("33F8D70EF472EEC8489CAA705837FA5F0156BF70CFD371FD", HEX);

    var signature = new ASN1(ASN1.SEQUENCE);
    signature.add(new ASN1(ASN1.INTEGER, r));
    signature.add(new ASN1(ASN1.INTEGER, s));

    assert(crypto.verify(key, Crypto.ECDSA_SHA1, message, signature.getBytes()));

## deriveKey()

### Prototype

void deriveKey (Key masterKey, Number mech, ByteString data, Key derivedKey)

### Description

Derive key from a master key using the mechanism specified and data for diversification.

The resulting DES key is parity adjusted, so that the number of 1 bits in each byte of the key value is odd.

This method can be used to calculate a public key (point) by multiplying the point with a skalar value and adding a second point (EC_MULTIPLY_ADD). This method is used in the PACE protocol to determine a temporary generator point using the formular G' = s * G + P. The variant EC_MULTIPLY_SUB performs a substration instead of an addition.

The parameter G is the point from the masterKey, the point P is provided by the public key value in derivedKey and the skalar value s is provided in the argument data. The result is stored as public key value in derivedKey.

If the public point P is undefined, then only the skalar multiplication is performed. If the argument data is null, then only the point addition is performed.

### Arguments

Type | Name | Description
--- | --- | ---
`Key` | masterKey | Master key to use for derivation algorithm
`Number` | mech | Derivation algorithm. Must be Crypto.DES_CBC or Crypto.DES_ECB.
`ByteString` | data | Derivation data. The length of the derivation data determines the length of the resulting key (8/16 or 24 Bytes). For method EC_MULTIPLY_ADD the argument determines the skalar value. If data is null, then the skalar multiplication is skipped and only the point addition is performed.
`Key` | derivedKey | The key object to store the resulting key value.

### Return

`None` | The method does not return data

### Exceptions

Name | Value | Description
--- | --- | ---
GPError | GPError.ARGUMENTS_MISSING | Too few arguments in call
GPError | GPError.INVALID_ARGUMENTS | Too many arguments in call
GPError | GPError.INVALID_TYPE | Type of argument is invalid for method invocation

### Example

    // Instantiate crypto service
    var crypto = new Crypto();

    // Create a single DES key, a double DES key and a triple DES key
    var des1key = new Key("profiles/kp_single_des_1.xml");
    var des2key = new Key("profiles/kp_double_des.xml");
    var des3key = new Key("profiles/kp_triple_des.xml");

    // Define derivation parameter
    var dpara8  = new ByteString("0102030405060708", HEX);
    var dpara16 = new ByteString("01020304050607081020304050607080", HEX);
    var dpara24 = new ByteString("010203040506070810203040506070801122334455667788", HEX);

    var derivedKey = new Key();
    var reference;

    // Derive a single DES key
    crypto.deriveKey(des1key, Crypto.DES_ECB, dpara8, derivedKey);
    reference = crypto.encrypt(des1key, Crypto.DES_ECB, dpara8);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a double DES key
    crypto.deriveKey(des1key, Crypto.DES_ECB, dpara16, derivedKey);
    reference = crypto.encrypt(des1key, Crypto.DES_ECB, dpara16);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a triple DES key
    crypto.deriveKey(des1key, Crypto.DES_ECB, dpara24, derivedKey);
    reference = crypto.encrypt(des1key, Crypto.DES_ECB, dpara24);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a single DES key
    crypto.deriveKey(des2key, Crypto.DES_ECB, dpara8, derivedKey);
    reference = crypto.encrypt(des2key, Crypto.DES_ECB, dpara8);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a double DES key
    crypto.deriveKey(des2key, Crypto.DES_ECB, dpara16, derivedKey);
    reference = crypto.encrypt(des2key, Crypto.DES_ECB, dpara16);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a triple DES key
    crypto.deriveKey(des2key, Crypto.DES_ECB, dpara24, derivedKey);
    reference = crypto.encrypt(des2key, Crypto.DES_ECB, dpara24);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a single DES key
    crypto.deriveKey(des3key, Crypto.DES_ECB, dpara8, derivedKey);
    reference = crypto.encrypt(des3key, Crypto.DES_ECB, dpara8);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a double DES key
    crypto.deriveKey(des3key, Crypto.DES_ECB, dpara16, derivedKey);
    reference = crypto.encrypt(des3key, Crypto.DES_ECB, dpara16);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a triple DES key
    crypto.deriveKey(des3key, Crypto.DES_ECB, dpara24, derivedKey);
    reference = crypto.encrypt(des3key, Crypto.DES_ECB, dpara24);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    var iv = new ByteString("0000000000000000", HEX);

    // Derive a single DES key
    crypto.deriveKey(des1key, Crypto.DES_CBC, dpara8, derivedKey);
    reference = crypto.encrypt(des1key, Crypto.DES_CBC, dpara8, iv);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a double DES key
    crypto.deriveKey(des1key, Crypto.DES_CBC, dpara16, derivedKey);
    reference = crypto.encrypt(des1key, Crypto.DES_CBC, dpara16, iv);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a triple DES key
    crypto.deriveKey(des1key, Crypto.DES_CBC, dpara24, derivedKey);
    reference = crypto.encrypt(des1key, Crypto.DES_CBC, dpara24, iv);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a single DES key
    crypto.deriveKey(des2key, Crypto.DES_CBC, dpara8, derivedKey);
    reference = crypto.encrypt(des2key, Crypto.DES_CBC, dpara8, iv);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a double DES key
    crypto.deriveKey(des2key, Crypto.DES_CBC, dpara16, derivedKey);
    reference = crypto.encrypt(des2key, Crypto.DES_CBC, dpara16, iv);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a triple DES key
    crypto.deriveKey(des2key, Crypto.DES_CBC, dpara24, derivedKey);
    reference = crypto.encrypt(des2key, Crypto.DES_CBC, dpara24, iv);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a single DES key
    crypto.deriveKey(des3key, Crypto.DES_CBC, dpara8, derivedKey);
    reference = crypto.encrypt(des3key, Crypto.DES_CBC, dpara8, iv);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a double DES key
    crypto.deriveKey(des3key, Crypto.DES_CBC, dpara16, derivedKey);
    reference = crypto.encrypt(des3key, Crypto.DES_CBC, dpara16, iv);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Derive a triple DES key
    crypto.deriveKey(des3key, Crypto.DES_CBC, dpara24, derivedKey);
    reference = crypto.encrypt(des3key, Crypto.DES_CBC, dpara24, iv);
    assert(keyequals(derivedKey.getComponent(Key.DES), reference));

    // Calculate a new point by multiplying G with skalar s and adding P.
    // This method is used to implement PACE as defined by the
    // Extended Access Control 2.x specification

    var P = new Key();
    P.setComponent(Key.ECC_CURVE_OID, new ByteString("1.3.36.3.3.2.8.1.1.5", OID));
    P.setComponent(Key.ECC_QX, new ByteString(
                "A99D861875FDCAF2406B6CE4423C1FE2EB4396A8636CF039C723DDEE", HEX));
    P.setComponent(Key.ECC_QY, new ByteString(
                "634A17EA9EC0DC8611EF51CDF46E8247C64A2B9F8ECFCE53B690ADC0", HEX));

    var G = new Key();
    G.setComponent(Key.ECC_CURVE_OID, new ByteString("1.3.36.3.3.2.8.1.1.5", OID));
    G.setComponent(Key.ECC_QX, P.getComponent(Key.ECC_GX));
    G.setComponent(Key.ECC_QY, P.getComponent(Key.ECC_GY));

    var s = new ByteString("3924D2D1E31CE13C", HEX);

    // Calculate G' = s * G + P
    crypto.deriveKey(G, Crypto.EC_MULTIPLY_ADD, s, P);

    // This method does not change the generator point directly, but the public key point
    // in the derived key. For PACE the public key point ECC_QX/Y must be copied
    // to ECC_GX/Y !
    assert(P.getComponent(Key.ECC_QX).toString(HEX) ==
                "992042B9D17CBDFA5915EAE4292E62A3F6582071622371F47C2C717E");
    assert(P.getComponent(Key.ECC_QY).toString(HEX) ==
                "16FC907BD3D87C7F45F56533DE33909A3A1D1E25487615284BC741E7");

    var G1 = new Key();
    G1.setType(Key.PUBLIC);
    G1.setComponent(Key.ECC_CURVE_OID, new ByteString("1.3.36.3.3.2.8.1.1.5", OID));

    var G = new Key();
    G.setComponent(Key.ECC_CURVE_OID, new ByteString("1.3.36.3.3.2.8.1.1.5", OID));
    G.setComponent(Key.ECC_QX, P.getComponent(Key.ECC_GX));
    G.setComponent(Key.ECC_QY, P.getComponent(Key.ECC_GY));

    var s = new ByteString("3924D2D1E31CE13C", HEX);

    // Calculate G'' = s * G
    crypto.deriveKey(G, Crypto.EC_MULTIPLY_ADD, s, G1);

    var P = new Key();
    P.setComponent(Key.ECC_CURVE_OID, new ByteString("1.3.36.3.3.2.8.1.1.5", OID));
    P.setComponent(Key.ECC_QX, new ByteString(
                "A99D861875FDCAF2406B6CE4423C1FE2EB4396A8636CF039C723DDEE", HEX));
    P.setComponent(Key.ECC_QY, new ByteString(
                "634A17EA9EC0DC8611EF51CDF46E8247C64A2B9F8ECFCE53B690ADC0", HEX));

    //Calculate G'' = G'' + P
    crypto.deriveKey(G1, Crypto.EC_MULTIPLY_ADD, null, P);

    assert(P.getComponent(Key.ECC_QX).toString(HEX) ==
                "992042B9D17CBDFA5915EAE4292E62A3F6582071622371F47C2C717E");
    assert(P.getComponent(Key.ECC_QY).toString(HEX) ==
                "16FC907BD3D87C7F45F56533DE33909A3A1D1E25487615284BC741E7");

## digest()

### Prototype

ByteString digest(Number mech, ByteString data, Number iterations)

### Description

Calculate message digest for data using hash algorithm specified in argument mech.

### Arguments

Type | Name | Description
--- | --- | ---
`Number` | mech | Digest algorithm. Must be either Crypto.SHA_x or Crypto.MD5.
`ByteString` | data | Message to process
`Number` | iterations | Optional parameter defining the number of iterations to perform with the previous result as input for the next round (Default 1). This is an extension to the GP specification.

### Return

`ByteString` | Message digest for given data

### Exceptions

Name | Value | Description
--- | --- | ---
GPError | GPError.ARGUMENTS_MISSING | Too few arguments in call
GPError | GPError.INVALID_ARGUMENTS | Too many arguments in call
GPError | GPError.INVALID_TYPE | Type of argument is invalid for method invocation
GPError | GPError.INVALID_MECH | The mechanism is invalid

### Example

    var message = new ByteString("Hello World", ASCII);
    var hash = crypto.digest(Crypto.SHA_1, message);
    print("SHA1: " + hash);
    var hash = crypto.digest(Crypto.MD5, message);
    print("MD5: " + hash);

    var message = new ByteString("", HEX);
    var ref = new ByteString("da39a3ee5e6b4b0d3255bfef95601890afd80709", HEX);
    var hash = crypto.digest(Crypto.SHA_1, message);
    assert(ref.equals(hash));

    var message = new ByteString("61", HEX);
    var ref = new ByteString("86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", HEX);
    var hash = crypto.digest(Crypto.SHA_1, message);
    assert(ref.equals(hash));

    var message = new ByteString("616263", HEX);
    var ref = new ByteString("a9993e364706816aba3e25717850c26c9cd0d89d", HEX);
    var hash = crypto.digest(Crypto.SHA_1, message);
    assert(ref.equals(hash));

    var message = new ByteString(
                "6162636465666768696a6b6c6d6e6f707172737475767778797a", HEX);
    var ref = new ByteString("32d10c7b8cf96570ca04ce37f2a19d84240d3a89", HEX);
    var hash = crypto.digest(Crypto.SHA_1, message);
    assert(ref.equals(hash));

    var message = new ByteString("616263", HEX);
    var ref = new ByteString(
                "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", HEX);
    var hash = crypto.digest(Crypto.SHA_224, message);
    assert(ref.equals(hash));

    var message = new ByteString("616263", HEX);
    var ref = new ByteString(
                "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", HEX);
    var hash = crypto.digest(Crypto.SHA_256, message);
    assert(ref.equals(hash));

    var message = new ByteString("616263", HEX);
    var ref = new ByteString(
                "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded163" +
                "1a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", HEX);
    var hash = crypto.digest(Crypto.SHA_384, message);
    assert(ref.equals(hash));

    var message = new ByteString("616263", HEX);
    var ref = new ByteString(
                "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
                "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", HEX);
    var hash = crypto.digest(Crypto.SHA_512, message);
    assert(ref.equals(hash));

    var message = new ByteString("", HEX);
    var ref = new ByteString("d41d8cd98f00b204e9800998ecf8427e", HEX);
    var hash = crypto.digest(Crypto.MD5, message);
    assert(ref.equals(hash));

    var message = new ByteString("61", HEX);
    var ref = new ByteString("0cc175b9c0f1b6a831c399e269772661", HEX);
    var hash = crypto.digest(Crypto.MD5, message);
    assert(ref.equals(hash));

    var message = new ByteString("616263", HEX);
    var ref = new ByteString("900150983cd24fb0d6963f7d28e17f72", HEX);
    var hash = crypto.digest(Crypto.MD5, message);
    assert(ref.equals(hash));

    var message = new ByteString(
                "6162636465666768696a6b6c6d6e6f707172737475767778797a", HEX);
    var ref = new ByteString("c3fcd3d76192e4007dfb496cca67e13b", HEX);
    var hash = crypto.digest(Crypto.MD5, message);
    assert(ref.equals(hash));

## generateKeyPair()

### Prototype

Void generateKeyPair(Number mech, Key pubKey, Key priKey)

### Description

Generate an asymmetric key pair according to the specification from the public key object.

For RSA key, the key size must be defined using the Key.setSize() method.

For EC keys, the curve parameter must be set using the setComponent() method.

### Arguments

Type | Name | Description
--- | --- | ---
`Number` | mech | Type of key pair, must be either Crypto.RSA or Crypto.EC.

### Return

`Void` | The method does not return a value

### Exceptions

Name | Value | Description
--- | --- | ---
GPError | GPError.ARGUMENTS_MISSING | Too few arguments in call
GPError | GPError.INVALID_ARGUMENTS | Too many arguments in call
GPError | GPError.INVALID_TYPE | Type of argument is invalid for method invocation
GPError | GPError.INVALID_DATA | The type of key is invalid

### Example

    // RSA Example - Generate a 1024 bit RSA key pair

    // Create empty public key object and set size
    var pubKey = new Key();
    pubKey.setType(Key.PUBLIC);
    pubKey.setSize(1024);

    // Create empty private key object and set size
    var priKey = new Key();
    priKey.setType(Key.PRIVATE);

    // Generate key pair
    crypto.generateKeyPair(Crypto.RSA, pubKey, priKey);

    // Extract key components...
    var modulus = pubKey.getComponent(Key.MODULUS);
    print("RSA Modulus:");
    print(modulus);

    var publicexponent = pubKey.getComponent(Key.EXPONENT);
    print("RSA Public Exponent:");
    print(publicexponent);

    print("CRT prime P");
    var crt_p = priKey.getComponent(Key.CRT_P);
    print(crt_p);

    print("CRT prime Q");
    var crt_q = priKey.getComponent(Key.CRT_Q);
    print(crt_q);

    print("CRT prime exponent P");
    var crt_dp = priKey.getComponent(Key.CRT_DP1);
    print(crt_dp);

    print("CRT prime exponent Q");
    var crt_dq = priKey.getComponent(Key.CRT_DQ1);
    print(crt_dq);

    print("CRT coefficient pq");
    var crt_pq = priKey.getComponent(Key.CRT_PQ);
    print(crt_pq);

    // ... and reassemble in newly created key
    var pubKey = new Key();
    pubKey.setType(Key.PUBLIC);
    pubKey.setComponent(Key.MODULUS, modulus);
    pubKey.setComponent(Key.EXPONENT, publicexponent);

    var priKey = new Key();
    priKey.setType(Key.PRIVATE);
    priKey.setComponent(Key.CRT_P, crt_p);
    priKey.setComponent(Key.CRT_Q, crt_q);
    priKey.setComponent(Key.CRT_DP1, crt_dp);
    priKey.setComponent(Key.CRT_DQ1, crt_dq);
    priKey.setComponent(Key.CRT_PQ, crt_pq);
    priKey.setComponent(Key.EXPONENT, publicexponent);

    // Verify that keys still work
    var message = new ByteString("Hello World", ASCII);

    var cryptogram = crypto.sign(priKey, Crypto.RSA, message);

    assert(crypto.verify(pubKey, Crypto.RSA, message, cryptogram));

    // ECC Example - Generate a 192 bit key pair over the prime192v1 curve

    // Create empty public key object
    var pubKey = new Key();
    pubKey.setType(Key.PUBLIC);

    // Select prime192v1 curve using it's object identifier
    pubKey.setComponent(Key.ECC_CURVE_OID, new ByteString("1.2.840.10045.3.1.1", OID));

    // Print out the curve parameter selected
    print("Curve Fp:");
    print(pubKey.getComponent(Key.ECC_P));
    print("Curve A:");
    print(pubKey.getComponent(Key.ECC_A));
    print("Curve B:");
    print(pubKey.getComponent(Key.ECC_B));
    print("Parameter Gx:");
    print(pubKey.getComponent(Key.ECC_GX));
    print("Parameter Gy:");
    print(pubKey.getComponent(Key.ECC_GY));
    print("Parameter N:");
    print(pubKey.getComponent(Key.ECC_N));
    print("Parameter H:");
    print(pubKey.getComponent(Key.ECC_H));

    // Create empty private key object
    var priKey = new Key();
    priKey.setType(Key.PRIVATE);

    // Generate key pair
    crypto.generateKeyPair(Crypto.EC, pubKey, priKey);

    // Extract and print private and public key values
    print("Public Key Qx:");
    var qx = pubKey.getComponent(Key.ECC_QX);
    assert(qx.length == 24);
    print(qx.toString(HEX));
    var qy = pubKey.getComponent(Key.ECC_QY);
    assert(qy.length == 24);
    print("Public Key Qy:");
    print(qy.toString(HEX));
    var d = priKey.getComponent(Key.ECC_D);
    print("Private Key D:");
    print(d.toString(HEX));

    // Reassemble keys
    var pubKey = new Key();
    pubKey.setType(Key.PUBLIC);
    pubKey.setComponent(Key.ECC_QX, qx);
    pubKey.setComponent(Key.ECC_QY, qy);
    pubKey.setComponent(Key.ECC_CURVE_OID, new ByteString("1.2.840.10045.3.1.1", OID));

    var priKey = new Key();
    priKey.setComponent(Key.ECC_D, d);
    priKey.setComponent(Key.ECC_CURVE_OID, new ByteString("1.2.840.10045.3.1.1", OID));

    // Test keys to verify integrity
    var message = new ByteString("Hello World", ASCII);

    var cryptogram = crypto.sign(priKey, Crypto.ECDSA_SHA1, message);

    assert(crypto.verify(pubKey, Crypto.ECDSA_SHA1, message, cryptogram));

    // ECC Example - Generate a 571 bit key pair over the secp521r1 curve

    // Create empty public key object
    var pubKey = new Key();
    pubKey.setType(Key.PUBLIC);

    // Select secp521r1 curve using it's object identifier
    pubKey.setComponent(Key.ECC_CURVE_OID, new ByteString("1.3.132.0.35", OID));

    // Print out the curve parameter selected
    print("Curve P:");
    print(pubKey.getComponent(Key.ECC_P));
    print("Curve A:");
    print(pubKey.getComponent(Key.ECC_A));
    print("Curve B:");
    print(pubKey.getComponent(Key.ECC_B));
    print("Parameter Gx:");
    print(pubKey.getComponent(Key.ECC_GX));
    print("Parameter Gy:");
    print(pubKey.getComponent(Key.ECC_GY));
    print("Parameter N:");
    print(pubKey.getComponent(Key.ECC_N));
    print("Parameter H:");
    print(pubKey.getComponent(Key.ECC_H));

    // Create empty private key object
    var priKey = new Key();
    priKey.setType(Key.PRIVATE);

    // Generate key pair
    crypto.generateKeyPair(Crypto.EC, pubKey, priKey);

    // Extract and print private and public key values
    print("Public Key Qx:");
    var qx = pubKey.getComponent(Key.ECC_QX);
    assert(qx.length == 66);
    print(qx.toString(HEX));
    var qy = pubKey.getComponent(Key.ECC_QY);
    assert(qy.length == 66);
    print("Public Key Qy:");
    print(qy.toString(HEX));
    var d = priKey.getComponent(Key.ECC_D);
    print("Private Key D:");
    print(d.toString(HEX));

    // Reassemble keys
    var pubKey = new Key();
    pubKey.setType(Key.PUBLIC);
    pubKey.setComponent(Key.ECC_QX, qx);
    pubKey.setComponent(Key.ECC_QY, qy);
    pubKey.setComponent(Key.ECC_CURVE_OID, new ByteString("1.3.132.0.35", OID));

    var priKey = new Key();
    priKey.setComponent(Key.ECC_D, d);
    priKey.setComponent(Key.ECC_CURVE_OID, new ByteString("1.3.132.0.35", OID));

    // Test keys to verify integrity
    var message = new ByteString("Hello World", ASCII);

    var cryptogram = crypto.sign(priKey, Crypto.ECDSA_SHA512, message);

    assert(crypto.verify(pubKey, Crypto.ECDSA_SHA512, message, cryptogram));

    var pubKey = new Key();
    pubKey.setType(Key.PUBLIC);
    // Select secp224k1 curve using it's object identifier
    pubKey.setComponent(Key.ECC_CURVE_OID, new ByteString("secp224k1", OID));

    print("Curve P:");
    print(pubKey.getComponent(Key.ECC_P));
    print("Curve A:");
    print(pubKey.getComponent(Key.ECC_A));
    print("Curve B:");
    print(pubKey.getComponent(Key.ECC_B));
    print("Parameter Gx:");
    print(pubKey.getComponent(Key.ECC_GX));
    print("Parameter Gy:");
    print(pubKey.getComponent(Key.ECC_GY));
    print("Parameter N:");
    print(pubKey.getComponent(Key.ECC_N));
    print("Parameter H:");
    print(pubKey.getComponent(Key.ECC_H));

    // Create empty private key object
    var priKey = new Key();
    priKey.setType(Key.PRIVATE);

    // Generate key pair
    crypto.generateKeyPair(Crypto.EC, pubKey, priKey);

    // Test keys to verify integrity
    var message = new ByteString("Hello World", ASCII);

    var cryptogram = crypto.sign(priKey, Crypto.ECDSA_SHA224, message);

    assert(crypto.verify(pubKey, Crypto.ECDSA_SHA224, message, cryptogram));

## generateRandom()

### Prototype

ByteString generateRandom(Number length)

### Description

Generate a ByteString of given length with random data

### Arguments

Type | Name | Description
--- | --- | ---
`Number` | length | Number of random bytes

### Return

`ByteString` | Returns length bytes of random data

### Exceptions

Name | Value | Description
--- | --- | ---
GPError | GPError.ARGUMENTS_MISSING | Too few arguments in call
GPError | GPError.INVALID_ARGUMENTS | Too many arguments in call
GPError | GPError.INVALID_TYPE | Type of argument is invalid for method invocation

### Example

    var val1 = crypto.generateRandom(10);
    assert(val1.length == 10);

    var val2 = crypto.generateRandom(10);
    assert(val2.length == 10);

    assert(val1 != val2);

© Copyright 2003 - 2026 CardContact Systems GmbH , Minden, Germany