I want to decrypt Public Key Certificate using a CA Public Key,
how can i get the output as below.
Recovered Data: 6A02457896FF12170314EF01019001E04E4FC478A42241068E2C9CFDEE9D7450F48F812FA66CEFB8ECBE31DD3C26C3B8A3891B77C1AA2A5A7448B869B7213D36C341E9B71302ADF478F67537032C080186C44034B1801D7644B6EEFAEA566D7336A8C83F42B7992F28BF5EA6B9D14C05870AD4DBD8CDAB8771F65F83D800B353B11E1805C7E4529F261C16A38DE756BC
Data Header: 6A
Data Format: 02
Issuer Identifier: 457896FF
Certificate Expiration Date: 1217
Certificate Serial Number: 0314EF
Hash Algorithm Indicator: 01
Issuer Public Key Algorithm Indicator: 01
Issuer Public Key Length: 90
Issuer Public Key Exponent Length: 01
Issuer Public Key: E04E4FC478A42241068E2C9CFDEE9D7450F48F812FA66CEFB8ECBE31DD3C26C3B8A3891B77C1AA2A5A7448B869B7213D36C341E9B71302ADF478F67537032C080186C44034B1801D7644B6EEFAEA566D7336A8C83F42B7992F28BF5EA6B9D14C05870AD4DBD8CDAB8771F65F
Hash Result: 83D800B353B11E1805C7E4529F261C16A38DE756
Data Trailer: BC
Download EMVCo Book 2, and read section 5 and 6.
Here you are trying to open an Issuer Public Key Certificate. Issuer Public Key certificate is opened using the Certification Authority Public Key. This key is located using RID and Index. You can find most here
Once CAPK is decided you have to use RSA reversible algorithm as mentioned in Annex B Approved Cryptographic Algorithms B2 Asymmetric Algorithms.
Related
I'm trying to manually create an ES256 JWT token. I've a small script written in python which signs a sha256 hash which uses ecdsa-python. But the signature is invalid on jwt.io.
Steps to reproduce:
Create base64 header + payload:
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0
Create SHA256 hash from the base64 header + payload:
FFC89E33091FFDD3C61798A0A74BF7C2D1A6FD231A6CB519F33952F7696BBE9F
Generate ec_private key:
openssl ec -in ec_private.pem -noout -text
Use the small python program to ecdsa sign the SHA256 hash
from json import dumps
from ellipticcurve.ecdsa import Ecdsa
from ellipticcurve.privateKey import PrivateKey
import base64
def toBase64Url(input):
return input.replace("+", "-").replace("/", "_").rstrip("=")
# Generate privateKey from PEM string
privateKey = PrivateKey.fromPem("""
-----BEGIN EC PARAMETERS-----
BgUrgQQACg==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJfChy9fKFItzqcb8DKBm+2oH0YTZ7N61SQpyABgVZANoAoGCCqGSM49
AwEHoUQDQgAE1TG2uvIMdfWkteiDWeHNYbQNSW/0uoYcvX4Z7ROUIgYRvgfpsjBa
Iv70SuYpmBLwl0AuEBoXIVTCclCme6SdEQ==
-----END EC PRIVATE KEY-----
""")
# Create message from json
message = "FFC89E33091FFDD3C61798A0A74BF7C2D1A6FD231A6CB519F33952F7696BBE9F"
signature = Ecdsa.sign(message, privateKey)
# Generate Signature in base64. This result can be sent to Stark Bank in the request header as the Digital-Signature parameter.
print("Base64: " + signature.toBase64())
print("Base64Url: " +toBase64Url(signature.toBase64()))
# To double check if the message matches the signature, do this:
publicKey = privateKey.publicKey()
print("Hash verification succesfull: " + str(Ecdsa.verify(message, signature, publicKey)))
The output:
Base64: MEQCIFyP4IoZGhzGfDCPX6fVxjtB+nrXDVhOTQwdc5vu8z4eAiBNalfGHqdaO3nCmTqimpAHF+IHzxk8em+OMMHrJkPOhA==
Base64Url: MEQCIFyP4IoZGhzGfDCPX6fVxjtB-nrXDVhOTQwdc5vu8z4eAiBNalfGHqdaO3nCmTqimpAHF-IHzxk8em-OMMHrJkPOhA
Hash verification succesfull: True
Check the signature in jwt.io gives Invalid signature
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.MEQCIFyP4IoZGhzGfDCPX6fVxjtB-nrXDVhOTQwdc5vu8z4eAiBNalfGHqdaO3nCmTqimpAHF-IHzxk8em-OMMHrJkPOhA
Keys:
Public:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1TG2uvIMdfWkteiDWeHNYbQNSW/0
uoYcvX4Z7ROUIgYRvgfpsjBaIv70SuYpmBLwl0AuEBoXIVTCclCme6SdEQ==
-----END PUBLIC KEY-----
Private:
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJfChy9fKFItzqcb8DKBm+2oH0YTZ7N61SQpyABgVZANoAoGCCqGSM49
AwEHoUQDQgAE1TG2uvIMdfWkteiDWeHNYbQNSW/0uoYcvX4Z7ROUIgYRvgfpsjBa
Iv70SuYpmBLwl0AuEBoXIVTCclCme6SdEQ==
-----END EC PRIVATE KEY-----
I know that there are many jwt signing python libraries but the use of this is to understand how a jwt token is created.
EDIT:
As #Topaco pointed out this library uses curve secp256k1 instead of secp256r1. secp256r1 | prime256v1 | NIST P-256 are all different names chosen by different standards organizations for the same curve (Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS)). I changed the library to python-ecdsa and the code to:
from ecdsa import SigningKey, NIST256p
import base64
def toBase64Url(input):
return input.replace("+", "-").replace("/", "_").rstrip("=")
sk = SigningKey.from_pem("""
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJfChy9fKFItzqcb8DKBm+2oH0YTZ7N61SQpyABgVZANoAoGCCqGSM49
AwEHoUQDQgAE1TG2uvIMdfWkteiDWeHNYbQNSW/0uoYcvX4Z7ROUIgYRvgfpsjBa
Iv70SuYpmBLwl0AuEBoXIVTCclCme6SdEQ==
-----END EC PRIVATE KEY-----
""")
vk = VerifyingKey.from_pem("""
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1TG2uvIMdfWkteiDWeHNYbQNSW/0
uoYcvX4Z7ROUIgYRvgfpsjBaIv70SuYpmBLwl0AuEBoXIVTCclCme6SdEQ==
-----END PUBLIC KEY-----
""")
signature = sk.sign(b"FFC89E33091FFDD3C61798A0A74BF7C2D1A6FD231A6CB519F33952F7696BBE9F")
print(base64.b64encode(signature))
print("Base64: " + base64.b64encode(signature).decode("utf-8"))
print("Base64Url: " + toBase64Url(base64.b64encode(signature).decode("utf-8")))
assert vk.verify(signature, b"FFC89E33091FFDD3C61798A0A74BF7C2D1A6FD231A6CB519F33952F7696BBE9F")
print("Hash verification succesfull: " + str(vk.verify(signature, b"FFC89E33091FFDD3C61798A0A74BF7C2D1A6FD231A6CB519F33952F7696BBE9F")))
The output:
Base64: rMBgC0ismGdd5rd7n1L+LDsQ2UO5+cjBwPNYh+xBZvO6fKoJIfmfyNpxw+kxmyKWlK+55dF5eMH1u327DMJvvA==
Base64Url: rMBgC0ismGdd5rd7n1L-LDsQ2UO5-cjBwPNYh-xBZvO6fKoJIfmfyNpxw-kxmyKWlK-55dF5eMH1u327DMJvvA
Hash verification succesfull: True
But the signature is still invalid.
The library you are using hashes implicitly, applying SHA1 by default. I.e. for compatibility with ES256 SHA256 must be explicitly specified and the unhashed JWT must be used, e.g.:
from ecdsa import SigningKey, VerifyingKey
import base64
from hashlib import sha256
def toBase64Url(input):
return input.replace("+", "-").replace("/", "_").rstrip("=")
jwt = b"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0"
sk = SigningKey.from_pem("""
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJfChy9fKFItzqcb8DKBm+2oH0YTZ7N61SQpyABgVZANoAoGCCqGSM49
AwEHoUQDQgAE1TG2uvIMdfWkteiDWeHNYbQNSW/0uoYcvX4Z7ROUIgYRvgfpsjBa
Iv70SuYpmBLwl0AuEBoXIVTCclCme6SdEQ==
-----END EC PRIVATE KEY-----
""")
vk = VerifyingKey.from_pem("""
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1TG2uvIMdfWkteiDWeHNYbQNSW/0
uoYcvX4Z7ROUIgYRvgfpsjBaIv70SuYpmBLwl0AuEBoXIVTCclCme6SdEQ==
-----END PUBLIC KEY-----
""")
signature = sk.sign(jwt, hashfunc=sha256)
print("Base64: " + base64.b64encode(signature).decode("utf-8"))
print("Base64Url: " + toBase64Url(base64.b64encode(signature).decode("utf-8")))
assert vk.verify(signature, jwt, hashfunc=sha256)
print("Hash verification succesfull: " + str(vk.verify(signature, jwt, hashfunc=sha256)))
A possible output is:
Base64: Mr4/DF87ek66E2GcAc+2H3ulHplCnxygz65h9dkdvm8QsZBbm2N5EjIgyiWsynza9zCGjjnzBUiXYvij9LLikA==
Base64Url: Mr4_DF87ek66E2GcAc-2H3ulHplCnxygz65h9dkdvm8QsZBbm2N5EjIgyiWsynza9zCGjjnzBUiXYvij9LLikA
Hash verification succesfull: True
The resulting signed token
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.Mr4_DF87ek66E2GcAc-2H3ulHplCnxygz65h9dkdvm8QsZBbm2N5EjIgyiWsynza9zCGjjnzBUiXYvij9LLikA
can then be successfully verified on https://jwt.io/ with the public key used here.
Here's something I don't understand.
I've played with some code examples on how to encrypt a string in the browser and decrypt the ciphered text on the server and I don't see how this is secure at all.
All of the examples assume that the same iv and the key used to encrypt the string will be sent to the server so it knows how to decrypt it.
Isn't that like taping the keys to the safe?
Am I supposed to send the iv and key object with the payload, along with the encrypted string?
I have to be missing something here.
async function generateKey() {
return await window.crypto.subtle.generateKey({
name: "AES-CBC",
length: 256
},
false,
["encrypt", "decrypt"]);
}
async function encryptString(data, key, iv) {
return await window.crypto.subtle.encrypt(
{
name: "AES-CBC",
iv,
},
key,
data
);
}
async function decryptString(data, key, iv) {
const decrypted = await window.crypto.subtle.decrypt(
{
name: "AES-CBC",
iv,
},
key,
data
);
return new TextDecoder("utf-8").decode(new Uint8Array(decrypted));
}
async function example() {
try {
// Create the IV and Key
const iv = window.crypto.getRandomValues(new Uint8Array(16));
const key = await generateKey();
// Convert the string I want to encrypt into an ArrayBuffer
const data = new TextEncoder("utf-8").encode('Hello World!');
// Encrypt the ArrayBuffer
const ciphertext = await encryptString(data, key, iv);
console.log(ciphertext);
// Now I decrypt the obscured string using the same key and iv I used to encrypt it.
const decrypted = await decryptString(ciphertext, key, iv);
// Hello World!
console.log(decrypted);
} catch(error) {
console.log(error);
}
}
Actually, the Symmetric Key between browser and server must be established using Asymmetric key first.
Like HTTS (TLS or SSL) is encrypted channel using Asymmetric key (Public key at Browser and Private key at server).
Thus you may rely on Encrypted Channel using HTTPS (TLS) to protect your Symmetric keys or alternatively, you may develop your own mechanism to protect it using Asymmetric keys, for which you will have to generate pair of keys (common for all users - at server or for every user), publish public key to clients and clients will use that public key to encrypt Symmetric key (and iv) which you will decrypt using server side private key. Once Asymmetric key is established, you can use it for fixed duration as per security requirements and then repeat the process, say after every 1 hour or 6 hours or 24 hours, etc.
for the implementation of an API I use, I need to provide a certificate, which consists of 2 byte arrays one for the public key and the other one for private key.
My initial idea was to do this with X509Certificate object of .Net. But I am struggling to get the private key bytes.
var certificate = new X509Certificate2("testCert.pfx", password, X509KeyStorageFlags.Exportable);
byte[] myPublicKey = certificate.GetRawCertData();
byte[] privateKey = ???
I've tried to export the key, but I can't export the private key standalone.
And:
certificate.PrivateKey.ToXmlString(true);
is not available on a Ubuntu System :-(
Do you have any ideas, how to get the private bytes from certificates?
May be X509Certificate2 is not the best solution for this...
Use an approrpiate method of these X509Certificate2 extension methods:
GetRSAPrivateKey(X509Certificate2) -- for RSA keys
GetDSAPrivateKey(X509Certificate2) -- for DSA keys
GetECDsaPrivateKey(X509Certificate2) -- for EC keys
Extension method you need to use depends on asymmtric key algorithm.
I'm getting the following exception when i try to encrypt a byte array with a EC public key :
java.security.InvalidKeyException: No installed provider supports this key:
sun.security.ec.ECPublicKeyImpl
This exception is generated when i call Cipher.init(). The lines below show what I did in my program:
ECPublicKey publicKey ;
ECPrivateKey privateKey;
//Generating key paire (public and private keys)
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "SunEC");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keyGen.initialize(571, random);
KeyPair pair = keyGen.generateKeyPair();
privateKey = (ECPrivateKey) pair.getPrivate();
publicKey = (ECPublicKey) pair.getPublic();
// get an AES cipher object with CTR encription mode
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
// encrypt the sharedSecret using the public key
cipher.init(Cipher.ENCRYPT_MODE, publicKey);**
byte[] result = cipher.doFinal(data);
Must I add a provider to support this public key ??
Finally, I found the source of this exception. The problem was initialization of cipher :
//This is the wrong initialization
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
//This is the right initialization
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding","SunJCE");
But now, i have another exception which is (it is less important than the previous one) :
java.security.InvalidKeyException: Invalid AES key length: 170 bytes
So what must I use as encrypting algorithm with ECDSA public key now ?
I read a simplification about how public and private keys work on security.stackexchange.com: How can I explain the concept of public and private keys without technical jargon?.
Whatever I understood from there: private key sat at owner and owner send a encrypted data to some one along with public key. Public key decrypts that data at client side and also encrypt data of client sent to owner. Once the data is encrypted at client side by public key then the same public key can not reused to encrypt that data. Only the owner of the private key can encrypt and decrypt data as many as time.
Am I right whatever I understood?
My question is: how public key is travel from owner side to client side?
Every time the same public key will be sent from server end to client end or ever time the different public key will be send from server end to client end?
#Ewan said as follows:
Client : Sends "Hello"
Server : Here is my public key
Server : Please send your public key
Client : Here is my (encrypted with server public key)public key
Client : Here is an (encrypted with server public key)request
Server : Here is an (encrypted with client public key)response
This raises the following questions at said steps:
When first time client send Hello to server then how hello
will travel to server in encrypted way?
Do not understand why server find his public key?
Why server request client to send his public key?
No you are wrong:
PersonA : creates public and private key pair
PersonA : Sends Public Key(A) to PersonB
PersonB : Encrypts data with Public Key(A)
PersonB : Sends encrypted Data to PersonA
PersonA : Decrypts encrypted Data with Private Key(A)
WCF can be setup to do multiple types of encryption and protocols but essentialy what i think you are asking boils down to
Handshake protocol:
Client : Sends "Hello" (not encrypted)
Server : Here is my public key (ServerPublicKEY = "123")
Server : Please send your public key
Client : Here is my public key (ClientPublicKEY = "ABC")
Client : Here is an (encrypted with ServerPublicKEY)request
Server : Decrypt with server private key and read
Server : Here is an (encrypted with ClientPublicKEY)response
Client : decrypt with client private key
to answer your additional questions
q1: "When first time client send Hello to server then how hello will travel to server in encrypted way?"
a1: It is not encrypted
q2: "Do not understand why server find his public key?"
a2: the server sends a public key so that the client can encrypt messages to send to the server
q3: "Why server request client to send his public key?"
a3: The server needs the clients public key so it can encrypt messages to send to the client