How to convert a JSON-encoded ECDSA private key to a SSH authentication key - ecdsa

I was given a SSH private key in this format, although I'm not familiar with any SSH clients that accept it as is.
{
"crv": "P-256",
"d": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"kid": "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx",
"kty": "EC",
"x": "xxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxx",
"y": "xxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxx"
}
How do I convert it to a .ppk file that PuTTY could read? I've tried just taking the d value that I understand to be the private key and using it to make a .pem formatted key, with both the BEGIN PRIVATE KEY and BEGIN EC PRIVATE KEY formats - starting with a BEGIN PRIVATE KEY file and using openssl ec -in test.pem -text to convert to the BEGIN EC PRIVATE KEY format, and PuTTYgen would not accept either file.
I've also tried to just manually fill out a .ppk file, which also so far hasn't worked. I'm guessing I don't have the right Private-MAC value because everything else seemed pretty straightforward...
PuTTY-User-Key-File-3: ecdsa-sha2-nistp256
Encryption: none
Comment: ecdsa-key-20221204
Public-Lines: 3
publickeyxxxxxxx
xxxxxxxx
xxxxxxx
Private-Lines: 1
privatexxxxxxxxxxxxxxxxx
Private-MAC: hmac-sha256(blank key, 'ecdsa-sha2-nistp256' + 'none' + 'ecdsa-key-20221204' + base64decode(publickeyxxxxxxxxxxxxxxxxxxxxxxxxxxxx) + base64decode(privatexxxxxxxxxxxxxxxxx))
What is the easiest way to convert this key into either a PPK or some other format that I can use with PuTTY?

Related

ECDSA signature generated with mbedtls not verifiable in JOSE (while code worked with RSA key)

I have a small application running on an ESP32 dev board (I use the Arduino IDE together with the shipped mbedtls) that issues and verifies JWT tokens. I have at first used RSA signatures successfully, but now wanted to go for shorter signatures and thus attempted to use ECDSA.
The application itself can issue tokens and verify them as well, but if I attempt to verify the tokens outside of my application - for instance with JOSE or the Debugger- I get verification failures and I cant quite wrap my head around why this is happening.
This is an example token (this token does practically not contain information):
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NzI0MTMxNjgsImV4cCI6MTY3MjQxNjc2OH0.MEUCIAjwEDXI424qjrAkSzZ_ydcVLOSAvfQ8YVddYvzDzMvQAiEAkVy4d-hZ01KpcMNKhPHk8E_SDYiB4JKwhm-Kc-Z81rI
This is the corresponding public key (this key is not used anywhere besides the purpose of presenting the issue here):
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUGnNIOhPhZZSOg4A4BqAFtGO13W4BGDQpQ0ieTvLU9/CXrY7W77o7pNx7tvugeIoYJxS0NjmxvT4TMpo4Z8P7A==
-----END PUBLIC KEY-----
As far as I understand, JWT tokens can be issued and verified using ECDSA. The so called "ES256" method is supposed to use prime256v1 in combination with SHA256, so I generated my key material with the following commands:
openssl ecparam -name prime256v1 -genkey -noout -out ecc-private.pem
openssl ec -in ecc-private.pem -pubout -out ecc-public.pem
For the signing part, the private key is loaded as follows, where ecc_priv is a String containing the PEM representation of the key:
//get the key
byte *keybuffer = (byte*)malloc((ecc_priv.length()+1)*sizeof(byte));
ecc_priv.getBytes(keybuffer, ecc_priv.length() + 1);
mbedtls_pk_context pk_context;
mbedtls_pk_init(&pk_context);
int rc = mbedtls_pk_parse_key(&pk_context, keybuffer, ecc_priv.length() + 1, NULL, 0);
if (rc != 0){
printf("Failed to mbedtls_pk_parse_key: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc));
return -1;
}
free(keybuffer);
Since this worked for me with RSA keys, I just replaced the keys and kept all other code to sign the actual message. As far as I understand, this should be possible with mbedtls_pk methods:
//mbedtls context
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_entropy_init(&entropy);
const char* pers="some entropy";
mbedtls_ctr_drbg_seed(
&ctr_drbg,
mbedtls_entropy_func,
&entropy,
(const unsigned char*)pers,
strlen(pers));
//get the header and payload bytes
byte *headerAndPayloadbytes = (byte*)malloc((headerAndPayload.length()+1)*sizeof(byte));
headerAndPayload.getBytes(headerAndPayloadbytes, headerAndPayload.length() + 1);
//prepare digest
uint8_t digest[32];
rc = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), headerAndPayloadbytes, headerAndPayload.length(), digest);
if (rc != 0) {
printf("Failed to mbedtls_md: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc));
return -1;
}
free(headerAndPayloadbytes);
//prepare output
byte *oBuf = (byte*)malloc(5000*sizeof(byte));
size_t retSize;
//sign digest
rc = mbedtls_pk_sign(&pk_context, MBEDTLS_MD_SHA256, digest, sizeof(digest), oBuf, &retSize, mbedtls_ctr_drbg_random, &ctr_drbg);
if (rc != 0) {
printf("Failed to mbedtls_pk_sign: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc));
return -1;
}
//encode signature to base64
unsigned int osize = encode_base64_length(retSize);
byte *output = (byte*)malloc((osize+1)*sizeof(byte));
encode_base64(oBuf, retSize, output);
String sig = String((char*)output);
free(output);
//base64 URL specific
sig.replace('+','-');
sig.replace('/','_');
sig.replace("=","");
String completejwt = headerAndPayload + "." + sig;
//free resources
mbedtls_ctr_drbg_free( &ctr_drbg );
mbedtls_entropy_free( &entropy );
mbedtls_pk_free(&pk_context);
free(oBuf);
My expectation was that I can simply replace the RSA keys with the ECDSA (prime256v1) keys and keep everything else as is, but the resulting token are not verifiable outside of my application. Again I want to emphasize that inside my application I can definitely verify the token and that the code worked perfectly fine with RSA keys, even outside my application. There must be something Im missing here, Im sure about that.
Any help or directions to research are highly appreciated.
EDIT: Here is a minimal compilable example (Arduino sketch)
Your ECDSA signature is a DER-encoded ASN.1 structure, rather than a simple r || s concatenation as proposed by IEEE-P1363 which is what the JOSE specification mandates.

Problem signing PDF with iText, PKCS11 and SHA-256 Algorithm

I'm trying to sign a pdf using PCKS11 (USB Token) and iText, It works fine when I use SHA-1 algorithm, the signature is valid and everything works fine however when I change it to SHA256 the signature is not valid, Does anyone know why? I'll put my code below:
PKCS11 pkcs11 = PKCS11.getInstance("C:\\Windows\\System32\\example.dll", "C_GetFunctionList", null,false);
long[] slotList = pkcs11.C_GetSlotList(true);
String providerString = "name=*\nlibrary=C:\\Windows\\System32\\example.dll\n" + "slot=" + slotList [0];
SunPKCS11 sunPKCS11 = new SunPKCS11(new ByteArrayInputStream(providerString .getBytes()));
Provider provider = sunPKCS11;
KeyStore keyStore = KeyStore.getInstance("PKCS11", provider);
keyStore.load(null, password);
keyStore.aliases();
Security.addProvider(keyStore.getProvider());
List<String> aliases = Collections.list(keyStore.aliases());
String alias = aliases.get(0);
PrivateKey pk = (PrivateKey)keyStore.getKey(alias,password);
Certificate[] certChain = new Certificate[1];
certChain[0] = signerCert;
PdfReader reader = new PdfReader(inputData);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
PdfStamper stamper = PdfStamper.createSignature(reader, outStream, '\0',null,true);
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
String fieldName = keyStore.getCertificateAlias(signerCert).replaceAll(".","");
appearance.setVisibleSignature(new Rectangle(420, 10, 70, 85), pageNumber,fieldName);
ExternalSignature es = new PrivateKeySignature(pk, DigestAlgorithms.SHA256,
keyStore.getProvider().getName());
ExternalDigest digest = new BouncyCastleDigest();
MakeSignature.signDetached(appearance,
digest, es,
certChain, null,
null, null,
0, CryptoStandard.CADES);
return outStream.toByteArray();
Why does it work with SHA-1 and not SHA-2? Where do you think the problem arises?
There are mismatches and errors in your signature.
download.pdf
This is the example file you shared in a comment to your question
Mismatch of Document Digest
The SHA-256 hash value of the signed bytes of your PDF is
9356BCD36F172806A3DCE7F062A66441E7C1DDC9203ABDAA0154A3F19208C8E3
but the embedded signature container claims it to be
5F892978FF2459157D631809A05F5DBCFCB55800236D2D5C3E4E4D94577012B4
According to your code that should not happen. Are you sure that PDF has been created by the code in your question? Or have you somehow changed it as you indicated by your I changed my hash like this comment and created the example document thereafter? Then this discrepancy most likely is caused by your change.
Broken Raw RSA Signature
After decrypting the raw signature bytes and removing the padding one gets
3031300D0609608648016503040201050004201DC71B824BAA3C7EC6744A0941CFADDAA893E8C1
This is incomplete. It corresponds to
SEQUENCE (2 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256 (NIST Algorithm)
NULL
OCTET STRING (32 byte) 1DC71B824BAA3C7EC6744A0941CFADDAA893E8C1XXXXXXXXXXXXXXXXXXXXXXXX
with the 12 bytes for that XXXXXXXXXXXXXXXXXXXXXXXX piece missing.
Thus, it looks like the signing device does not really support SHA256withRSA, at least not in combination with the example.dll PKCS#11 driver and the SunPKCS11 security provider.
As an aside, the OCTET STRING there should have been
EC7FCC5D003DFEC58B0ECB49CEEAD28495FFA8D798A1A88DA6051C1857B971EC
Thus, it looks like here is another mismatch, the 1DC71B824BAA3C7EC6744A0941CFADDAA893E8C1 actually there appears not to be related to this value.
SHA256.pdf
Can you check out this one? this one is made with itext's library and no code was changed.
In this file there indeed are no hash mismatches anymore, merely the signature value is cut off, here
3031300D0609608648016503040201050004204C8440B547E6A0EFD1489B8F5B5DFDA2DFA45DC1
corresponding to
SEQUENCE (2 elem)
SEQUENCE (2 elem)
OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256 (NIST Algorithm)
NULL
OCTET STRING (32 byte) 4C8440B547E6A0EFD1489B8F5B5DFDA2DFA45DC1XXXXXXXXXXXXXXXXXXXXXXXX
The complete OCTET STRING should have been
4C8440B547E6A0EFD1489B8F5B5DFDA2DFA45DC19048B5E53D468FE6A8E4E973
So apparently indeed the chain of your signing device, the example.dll PKCS#11 driver, and the SunPKCS11 security provider from your JRE does not support SHA256withRSA.

Xamarin ios, SSL pinning : Public key hash calculated does not match

We are trying to implement SSL pinning in our Xamarin.ios app.
POC : As a proof of concept, we calculated public key hash of https://www.google.co.uk . We used openssl s_client -servername www.google.co.uk -connect www.google.co.uk:443 | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64 command in terminal to get hash of public key (SHA256) .
We pinned this hash of public key for https://www.google.co.uk in our app inside our app and tried comparing it at runtime.
Then using NSURLSession we tried fetching data of https://www.google.co.uk .
Inside DidReceiveChallenge we calculate hash of public key using following code :
SecKey key = challenge.ProtectionSpace.ServerSecTrust.GetKey();
NSError error = new NSError();
NSData keyData = key.GetExternalRepresentation(out error);
string str = sha256(keyData);
That hash calculating function body is as below :
public string sha256(NSData data)
{
using (SHA256 mySHA256 = SHA256.Create())
{
byte[] bytes = data.ToArray();
byte[] hashvalue = mySHA256.ComputeHash(bytes);
NSData d = NSData.FromArray(hashvalue);
return d.GetBase64EncodedString(NSDataBase64EncodingOptions.SixtyFourCharacterLineLength);
}
}
But the hash returned by sha256 function written by us above does not match with the hash calculated using terminal command.
Are we doing something wrong in hash calculation.? We have also tried public key api, SecKey key = challenge.ProtectionSpace.ServerSecTrust.GetPublicKey();
We referred this article for this approach : https://medium.com/flawless-app-stories/ssl-pinning-254fa8ca2109 this article which uses Swift code for hash calculation.

External signature on a smart card

I am using a smart card that is signing a SHA-1 hash of a document, and compute a 256 bytes digital signature.
I am using the code posted on this question - iText signing PDF using external signature with smart card.
My problem is that I get the error:" The document has been altered or corrupted since the signature was applied".
I am using a GUI to create the hash and then send the signed 256 bytes that is computed on the card to the signing functions .
Here is my code:
hash creating code of filepath pdf document:
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
SHA256 sha2 = SHA256.Create();
//sha2.ComputeHash
byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath);
byte[] hash = null;
hash= sha1.ComputeHash(pdfBytes);
the above code is used in one of the GUI functions to create the hash of the document
namespace EIDSmartCardSign
{
class PdfSignature
{
private string outputPdfPath;
private string certPath;
byte[] messageDigest;
private string inputPdfPath;
public PdfSignature(byte[] messageDigest, string inputPdfPath,string outputPdfPath)
{
this.messageDigest = messageDigest;
this.outputPdfPath = outputPdfPath;
this.inputPdfPath = inputPdfPath;
}
public void setCertPath(string certPath)
{
this.certPath = certPath;
}
public void signPdf()
{
X509Certificate2 cert = new X509Certificate2();
cert.Import(certPath); // .cer file certificate obtained from smart card
X509CertificateParser certParse = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[1] ;
chain[0] = certParse.ReadCertificate(cert.RawData);
X509Certificate2[] certs;
PdfReader reader = new PdfReader(inputPdfPath);
FileStream fout = new FileStream(outputPdfPath,FileMode.Create);
PdfStamper stamper = PdfStamper.CreateSignature(reader, fout, '\0',null,true);
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.SignatureCreator = "Me";
appearance.Reason = "Testing iText";
appearance.Location = "On my Laptop";
iTextSharp.text.Rectangle rec = new iTextSharp.text.Rectangle(50, 50, 250, 100);
appearance.SetVisibleSignature(rec, 1, "Signature");
IExternalSignature extSignature= new MyExternalSignature("SHA-1",this.messageDigest);
MakeSignature.SignDetached(appearance, extSignature, chain, null, null, null, 0, CryptoStandard.CMS);
//MakeSignature.
}
}
}
Your hash creating function
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
SHA256 sha2 = SHA256.Create();
//sha2.ComputeHash
byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath);
byte[] hash = null;
hash = sha1.ComputeHash(pdfBytes);
calculates the wrong hash value.
Have a look at this answer on Information Security Stack Exchange, in particular the sketch
shows that to get the document bytes to sign you do not take the original PDF but instead have to prepare it for integrating the signature container (add signature field, field value with some space reserved for the signature container, and field visualization) and then hash all the bytes except the space reserved for the signature container.
Furthermore, even this naked hash is not the data to sign. Instead a set of attributes is built, one of them containing the document hash calculated as above, other ones containing references to the signer certificate etc., and these attributes are to be signed.
Thus, instead do what you already claimed to be doing:
I am using the code posted on this question - iText signing PDF using external signature with smart card.
In particular the code there does not sign the hash of the whole file but instead uses the data the method Sign of the IExternalSignature implementation receives as parameter which is constructed as explained above.
More details
In a comment the OP said
The card I am working with expects a 20 bytes hash.
20 bytes would be typical for a naked hash generated by either SHA1 or RIPEMD-160. According to your question text, I assume the former algorithm is used. (This by the way indicates that the context does not require a high security level as SHA1 effectively is already phased out or in the process of being phased out for such use cases.)
What steps are needed to further create this hash After hashing the contents of the pdf?
Simply do as in the IExternalSignature implementation in the question you referenced:
public virtual byte[] Sign(byte[] message) {
byte[] hash = null;
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
{
hash = sha1.ComputeHash(message);
}
byte[] sig = MySC.GetSignature(hash);
return sig;
}
(Obviously chances are that your smart card signing routine is not called MySC.GetSignature and you have to replace that call accordingly...)
As your card appears to expect a naked hash value in contrast to the card of the OP of the referenced question, this should work for you.
Where can I find examples of creating the aformentioned integrated signature container?
In the examples to the iText white paper Digital Signatures for PDF Documents.
After the signature process, I have 256 bytes signed data, 3 .cer certificates exported from the card.
256 bytes signed data sounds like a naked signature generated using RSA or RSASSA-PSS with a 2048 bit key size.
That been said, you need the signer certificate before signing: In most relevant profiles the signed attributes have to contain a reference to the signer certificate. In the code in the question you referenced that signer certificate is handled here
public void StartTest(){
X509Certificate2 cert = new X509Certificate2();
cert.Import("cert.cer"); // certificate obtained from smart card
X509CertificateParser certParse = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { certParse.ReadCertificate(cert.RawData) };
[...]
MyMakeSignature.SignDetached(appearance, externalSignature, chain, null, null, tsc, 0, CryptoStandard.CADES);
In particular you have to identify the correct signer certificate among those three certificate your card returns; otherwise you might have the same issue as the OP in the referenced question.
How do I create the Contents object when I have all of this data?
Considering what you said about your use case, chances are good that you really merely have to use the code posted of the question iText signing PDF using external signature with smart card with minor adaptions.

Types of VS FoxPro encodings

I'm trying to decode some strings in a DBF (created by a Foxpro app), and i'm interested in encoding / encrypting methods of FoxPro.
Here's a sample encoded string: "òÙÛÚÓ ½kê3ù[ƒ˜øžÃ+™Þoa-Kh— Gó¯ý""|øHñyäEük#‰fç9æ×ϯyi±:"
Can somebody tell me the encoding method of this string, OR give me any suggestion about Foxpro encoding methods?
Thanks!
It depends on the FoxPro version, the most recent DBF structure (VFP 9) is documented here:
https://msdn.microsoft.com/en-us/library/aa975386%28v=vs.71%29.aspx
It looks like your text could be the result of the "_Crypt.vcx" which will take a given string, apply whatever passphrase and generate an output encrypted string.
VFP has a class that is available in the "FFC" folder where VFP is default installed (via HOME() path resulting such as
C:\PROGRAM FILES (X86)\MICROSOFT VISUAL FOXPRO 9\
Here is a SAMPLE set of code to hook up the _Crypt class and sample to encrypt a string, then decrypt an encrypted string. Your string appears encrypted (obviously), but unless you know more of the encryption (such as finding the passphrase / key, you might be a bit stuck and into more research)...
lcCryptLib = HOME() + "FFC\_Crypt.vcx"
IF NOT FILE( lcCryptLib )
MESSAGEBOX( "No crypt class library." )
RETURN
ENDIF
SET CLASSLIB TO ( lcCryptLib ) ADDITIVE
oCrypt = CREATEOBJECT( "_CryptAPI" )
oCrypt.AddProperty( "myPassKey" )
oCrypt.myPassKey = "Hold property to represent some special 'Key/pass phrase' "
*/ Place-holder to get encrypted value
lcEncryptedValue = ""
? oCrypt.EncryptSessionStreamString( "Original String", oCrypt.myPassKey, #lcEncryptedValue )
*/ Show results of encrypted value
? "Encrypted Value: " + lcEncryptedValue
*/ Now, to get the decrypted from the encrypted...
lcDecryptedValue = ""
? oCrypt.DecryptSessionStreamString( lcEncryptedValue, oCrypt.myPassKey, #lcDecryptedValue )
? "Decrypted Value: " + lcDecryptedValue
*/ Now, try with your string to decrypt
lcYourString = [òÙÛÚÓ ½kê3ù[ƒ˜øžÃ+™Þoa-Kh— Gó¯ý""|øHñyäEük#‰fç9æ×ϯyi±:]
lcDecryptedValue = ""
? oCrypt.DecryptSessionStreamString( lcYourString, oCrypt.myPassKey, #lcDecryptedValue )
? "Decrypted Value: " + lcDecryptedValue