I tried to comment on this link https://stackoverflow.com/a/39798597/448266, but could not due to the reputation #.
I have tried the sample and run well, but when I changed to arbitrary value it returns exception Message: Net.Pkcs11Interop.Common.Pkcs11Exception : Method C_CreateObject returned 2147483968
I am using safenet HSM SW.
plainKeyValue = Common.HelperFunctions.StringToByteArray("112233445566778899001122334455665566998844335511");
Below is the snapshot of the code, I changed slightly on the key value (as above).
public static string generateAndCreateKeyObj()
{
using (IPkcs11 pkcs11 = Settings.Factories.Pkcs11Factory.CreatePkcs11(Settings.Factories, Configurations.Pkcs11LibraryPath, Settings.AppType))
{
// Find first slot with token present
ISlot slot = Helpers.GetUsableSlot(pkcs11, Configurations.default_slot);
// Open RW session
using (Net.Pkcs11Interop.HighLevelAPI.ISession session = slot.OpenSession(SessionType.ReadWrite))
{
// Login as normal user
session.Login(Configurations.user_type, "1234");
// Prepare attribute template of new key
List<IObjectAttribute> objectAttributes = new List<IObjectAttribute>();
objectAttributes.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_TOKEN, false)); //not stored in token
objectAttributes.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
objectAttributes.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
objectAttributes.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_ENCRYPT, true));
objectAttributes.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_DECRYPT, true));
objectAttributes.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_WRAP, true));
objectAttributes.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_UNWRAP, true));
objectAttributes.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_EXTRACTABLE, true));
// Specify key generation mechanism
IMechanism mechanism = Settings.Factories.MechanismFactory.CreateMechanism(CKM.CKM_DES3_KEY_GEN);
// Generate key
IObjectHandle secret_key = session.GenerateKey(mechanism, objectAttributes);
////////////////////////////////////////////////////////////////////////////////////////
// Export the key
byte[] plainKeyValue = null;
List<IObjectAttribute> readAttrs = session.GetAttributeValue(secret_key, new List<CKA>() { CKA.CKA_VALUE });
if (readAttrs[0].CannotBeRead)
throw new Exception("Key cannot be exported");
else
plainKeyValue = readAttrs[0].GetValueAsByteArray();
plainKeyValue = Common.HelperFunctions.StringToByteArray("112233445566778899001122334455665566998844335511");
// Prepare attribute template of new key
List<IObjectAttribute> oa = new List<IObjectAttribute>();
oa.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_LABEL, "Imported key"));
oa.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY));
oa.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3));
oa.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_TOKEN, true));
oa.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_ENCRYPT, true));
oa.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_DECRYPT, true));
oa.Add(Settings.Factories.ObjectAttributeFactory.CreateObjectAttribute(CKA.CKA_VALUE, plainKeyValue));
IObjectHandle importedKey = session.CreateObject(oa);
// Test encryption with generated key and decryption with imported key
using (IMechanism mechanismx = Settings.Factories.MechanismFactory.CreateMechanism(CKM.CKM_DES3_CBC, session.GenerateRandom(8)))
{
byte[] sourceData = ConvertUtils.Utf8StringToBytes("Our new password");
byte[] encryptedData = session.Encrypt(mechanismx, secret_key, sourceData);
byte[] decryptedData = session.Decrypt(mechanismx, importedKey, encryptedData);
if (Convert.ToBase64String(sourceData) != Convert.ToBase64String(decryptedData))
throw new Exception("Encryption test failed");
}
// Destroy object
session.DestroyObject(importedKey);
session.DestroyObject(secret_key);
session.Logout();
return HelperFunctions.ByteArrayToString(plainKeyValue);
}
}
}
// convert from string to array
public static byte[] StringToByteArray(string hex)
{
byte[] result;
try
{
result = Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
return result;
}
catch (Exception e)
{
throw new Exception(e.Message); ;
}
}
Exception you are getting says that low level PKCS#11 function C_CreateObject returned vendor specific error 0x80000140. You will need to discuss documentation provided by the device vendor or contact vendor support to get better understanding how to handle or avoid this specific error.
Thanks #jariq for your response.
I found out that in safenet hsm when creating a key object, the key plain value must be with odd parity bit, if not then the error mentioned above will occur.
Hope this will help anyone who stumbled the same error.
Related
I signed the pdf successfully and also verified the pdf successfully but the "SignName" property of class PdfPKCS7 always returns null.
I don't know why? Am I missing something during the pdf signing process or verification process?
//res.SignName always returns null.
validite = "Validated : " + res.SignName;
Pdf signing code see here: "Invalid algorithm specified" when pdf signing with Itext 5.5.13.2
and Verification Code is given below.
private void Button1_Click(object sender, EventArgs e)
{
PdfReader reader;
reader = new PdfReader(pdfFilePath.Text);
try
{
AcroFields acf = reader.AcroFields();
List<string> sgnoms = acf.GetSignatureNames();
List<string> sgnoms2 = acf.GetBlankSignatureNames();
Org.BouncyCastle.X509.X509Certificate cert;
if (sgnoms.Count > 0)
{
foreach (object obj in sgnoms)
{
PdfPKCS7 res = acf.VerifySignature(obj.ToString());
string validite = "Not Validate";
DateTime cal = res.SignDate;
if (res.SigningCertificate.IsValid(DateTime.Now) && res.Verify())
//res.SignName` Always returns null
validite = "Validated : " + res.SignName;
res = null;
validite = null;
cal = default(DateTime);
}
}
else
throw new Exception("Document not sign!");
reader = null;
acf = null;
sgnoms = null;
sgnoms2 = null;
}
catch (Exception ex)
{
}
}
Is any alternative to get the Signer Name? Or anything missing in the code?
Please check it, Unbale to get the reason. Am I missing something during the pdf signing process? or Am I missing something during the pdf verification process?
Any ideas, working code and suggestions are welcome.
Thanks in advance.
The SignName property is the value of the Name entry of the signature dictionary. This entry is specified as:
Key
Type
Value
Name
text string
(Optional) The name of the person or authority signing the document. This value should be used only when it is not possible to extract the name from the signature.EXAMPLE 1 From the certificate of the signer.
(ISO 32000-1, Table 252 – Entries in a signature dictionary)
This entry is optional, so the value you retrieve may well be null.
There is also a hint where you can look for the signer name here: in the signer certificate! Thus, consider inspecting the SigningCertificate property of your PdfPKCS7 object.
How can I achieve the very basic CSR Signing HSM functionality with Azure Key Vault?
I had found a very long and manual process to somehow achieve it:
Create a private key in Key Vault
Create a CSR, digest it with SHA256
Sign the digest with the previous private key using the Sign() method
Create a local x.509 cert and append the signature
Upload the new signed cert to Key Vault
Problem is, it is manual, long (also, quite a bit of latency) and error prone. Also I haven't found a single C# code example for this, and I'm looking for EC and not RSA.
The question is, is there a simple CertificateRequest.Sign() function in Key Vault? this seems to be so basic for an HSM-like service...
Thanks
This blog post by Vitaliy Slepakov describes a solution that he created which implements the steps you listed above using C#/.NET Core.
The code is available here:
https://github.com/vslepakov/keyvault-ca/
The heart of it is the following:
byte[] certificateRequest = /* ... */;
string issuerCertificateName = /* ... */;
KeyVaultServiceClient keyVaultServiceClient = /* ... */;
X509SignatureGenerator generator = /* see next section */;
var pkcs10CertificationRequest = new Pkcs10CertificationRequest(certificateRequest);
//TODO: Validate CSR via pkcs10CertificationRequest.Verify()
var info = pkcs10CertificationRequest.GetCertificationRequestInfo();
var notBefore = DateTime.UtcNow.AddDays(-1);
// Get the RSA public key from the CSR
var asymmetricKeyParameter = Org.BouncyCastle.Security.PublicKeyFactory.CreateKey(info.SubjectPublicKeyInfo);
var rsaKeyParameters = (Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)asymmetricKeyParameter;
var rsaKeyInfo = new RSAParameters
{
Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned(),
Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned()
};
var publicKey = RSA.Create(rsaKeyInfo);
//TODO: Validate publicKey
var certBundle = await keyVaultServiceClient.GetCertificateAsync(issuerCertificateName).ConfigureAwait(false);
var signingCert = new X509Certificate2(certBundle.Cer);
// new serial number
var serialNumber = new byte[SerialNumberLength];
RandomNumberGenerator.Fill(serialNumber);
serialNumber[0] &= 0x7F;
var subjectDN = new X500DistinguishedName(subjectName);
var request = new CertificateRequest(subjectDN, publicKey, GetRSAHashAlgorithmName(hashSizeInBits), RSASignaturePadding.Pkcs1);
// Basic constraints
request.CertificateExtensions.Add(
new X509BasicConstraintsExtension(caCert, caCert, 0, true));
// Subject Key Identifier
var ski = new X509SubjectKeyIdentifierExtension(
request.PublicKey,
X509SubjectKeyIdentifierHashAlgorithm.Sha1,
false);
request.CertificateExtensions.Add(ski);
// Authority Key Identifier
if (issuerCAKeyCert != null)
request.CertificateExtensions.Add(BuildAuthorityKeyIdentifier(issuerCAKeyCert));
else
request.CertificateExtensions.Add(BuildAuthorityKeyIdentifier(subjectDN, serialNumber.Reverse().ToArray(), ski));
if (caCert)
request.CertificateExtensions.Add(
new X509KeyUsageExtension(
X509KeyUsageFlags.DigitalSignature |
X509KeyUsageFlags.KeyCertSign |
X509KeyUsageFlags.CrlSign,
true));
else
{
// Key Usage
var defaultFlags =
X509KeyUsageFlags.DigitalSignature |
X509KeyUsageFlags.DataEncipherment |
X509KeyUsageFlags.NonRepudiation |
X509KeyUsageFlags.KeyEncipherment;
request.CertificateExtensions.Add(new X509KeyUsageExtension(defaultFlags, true));
// Enhanced key usage
request.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection {
new Oid("1.3.6.1.5.5.7.3.1"),
new Oid("1.3.6.1.5.5.7.3.2") }, true));
}
if (issuerCAKeyCert != null)
{
if (notAfter > issuerCAKeyCert.NotAfter)
{
notAfter = issuerCAKeyCert.NotAfter;
}
if (notBefore < issuerCAKeyCert.NotBefore)
{
notBefore = issuerCAKeyCert.NotBefore;
}
}
var issuerSubjectName = issuerCAKeyCert != null ? issuerCAKeyCert.SubjectName : subjectDN;
X509Certificate2 signedCert = request.Create(
issuerSubjectName,
generator,
notBefore,
notAfter,
serialNumber);
The custom X509SignatureGenerator implementation is here and used the following Key Vault SDK method:
HashAlgorithm hash = /* see GitHub */;
var digest = hash.ComputeHash(data);
var resultKeyVaultPkcs = await keyVaultClient.SignAsync(signingKey, algorithm, digest, RSASignaturePadding.Pkcs1);
Hopefully you can adapt this code to meet your needs. I'll be doing that as well. 😀
KV has a sign operation, but it's not specific to any data type (such as a cert request).
The KV .NET SDK offers this https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.keyvault.keyvaultclient.signwithhttpmessagesasync?view=azure-dotnet-legacy which is just a wrapper over REST APIs https://learn.microsoft.com/en-us/rest/api/keyvault/
This isn't exactly what you want, but I wrote some code to demonstrate C# KV encrypt/decrypt which should help you get started https://github.com/x509cert/AzureKeyVault
When signing data with RSACryptoServiceProvider in C#, I have a requirement to ensure the certificate was imported with strong key protection and a high security level to require the user enters the password every time they sign with the key. Here's a quick simplified sample of the signing code:
X509Store myCurrentUserStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
myCurrentUserStore.Open(OpenFlags.MaxAllowed);
X509Certificate2 currentCertificate = myCurrentUserStore.Certificates[4];
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.FromXmlString(currentCertificate.PrivateKey.ToXmlString(true));
byte[] signedData = Encoding.UTF8.GetBytes(originalFileContent);
byte[] signature = key.SignData(signedData, CryptoConfig2.CreateFromName("SHA256CryptoServiceProvider") as HashAlgorithm);
So what's the best way to go about checking how the certificate was installed so I can display an error message if it was not installed with strong private key protection with a high security level?
There are a couple things in your snippet that I don't understand.
Why you're opening with MaxAllowed. If you just want to read, use ReadOnly.
Why you're reading store.Certificates[4]. But presumably this is just a placeholder for "read a cert".
Why you're exporting and re-importing the key. (Especially since that would have had to prompt, which would defeat your "it needs to prompt" goal).
For #3 I'm assuming you are just looking to have a unique instance, in which case: Good news! .NET 4.6 added a GetRSAPrivateKey (extension) method to X509Certificate2 which always returns a unique instance. (And you might be excited to know about the new overload to SignData which doesn't encourage sending objects to the finalizer queue: https://msdn.microsoft.com/en-us/library/mt132675(v=vs.110).aspx)
Anyways, what I wrote here works for medium (consent) or high (password) protection. The CngKey based approach can distinguish medium from high, but the classic CAPI fallback can't tell which is which. (The classic CAPI fallback will only happen with obscure HSMs which don't have a CNG-compatible driver).
private static bool HasProtectedKey(X509Certificate2 cert)
{
if (!cert.HasPrivateKey)
{
return false;
}
using (RSA rsa = cert.GetRSAPrivateKey())
{
return HasProtectedKey(rsa);
}
}
private static bool HasProtectedKey(RSA rsa)
{
RSACng rsaCng = rsa as RSACng;
if (rsaCng != null)
{
return rsaCng.Key.UIPolicy.ProtectionLevel != CngUIProtectionLevels.None;
}
RSACryptoServiceProvider rsaCsp = rsa as RSACryptoServiceProvider;
if (rsaCsp != null)
{
CspKeyContainerInfo info = rsaCsp.CspKeyContainerInfo;
// First, try with the CNG API, it can answer the question directly:
try
{
var openOptions = info.MachineKeyStore
? CngKeyOpenOptions.MachineKey
: CngKeyOpenOptions.UserKey;
var cngProvider = new CngProvider(info.ProviderName);
using (CngKey cngKey =
CngKey.Open(info.KeyContainerName, cngProvider, openOptions))
{
return cngKey.UIPolicy.ProtectionLevel != CngUIProtectionLevels.None;
}
}
catch (CryptographicException)
{
}
// Fallback for CSP modules which CNG cannot load:
try
{
CspParameters silentParams = new CspParameters
{
KeyContainerName = info.KeyContainerName,
KeyNumber = (int)info.KeyNumber,
ProviderType = info.ProviderType,
ProviderName = info.ProviderName,
Flags = CspProviderFlags.UseExistingKey | CspProviderFlags.NoPrompt,
};
if (info.MachineKeyStore)
{
silentParams.Flags |= CspProviderFlags.UseMachineKeyStore;
}
using (new RSACryptoServiceProvider(silentParams))
{
}
return false;
}
catch (CryptographicException e)
{
const int NTE_SILENT_CONTEXT = unchecked((int)0x80090022);
if (e.HResult == NTE_SILENT_CONTEXT)
{
return true;
}
throw;
}
}
// Some sort of RSA we don't know about, assume false.
return false;
}
I cant get a batch scanner to only scan for a specific row, when settings start and stop keys to the same thing I get no entry's back, when using an scanner I get this exception:
"java.lang.IllegalArgumentException: Start key must be less than end key in range (Test : [] 0 false, Test : [] 0 false)"...
I am writing in C# in Visual Studio 2010 and using Thrift (ver 0.9.1.1) and Accumulo's (ver 1.5.0) proxy.thrift code in the project.
Here is my code, everything "works" but I don't get any entries from client.nextK
class Program
{
static byte[] GetBytes(string str)
{
return Encoding.ASCII.GetBytes(str);
}
static string GetString(byte[] bytes)
{
return Encoding.ASCII.GetString(bytes);
}
static void Main(string[] args)
{
try
{
/** connect **/
TTransport transport = new TSocket("192.168.58.62", 42424);
transport = new TFramedTransport(transport);
TCompactProtocol protocol = new TCompactProtocol(transport);
transport.Open();
AccumuloProxy.Client client = new AccumuloProxy.Client(protocol);
Dictionary<string, string> passwd = new Dictionary<string,string>();
passwd.Add("password", "password");
var login = client.login("root", passwd);
/** connect end **/
/** Get all data from one "Row" **/
var bScanner = new BatchScanOptions();
Range range = new Range();
range.Start = new Key();
range.Start.Row = GetBytes("Test");
range.Stop = new Key();
range.Stop.Row = GetBytes("Test");
bScanner.Ranges = new List<Range>();
bScanner.Ranges.Add(range);
var scanId = client.createBatchScanner(login, "firstTable", bScanner);
var more = true;
while (more)
{
var scan = client.nextK(scanId, 10);
more = scan.More;
foreach (var entry in scan.Results)
{
Console.WriteLine("{0} {1}:{2} [{3}] {4}", GetString(entry.Key.Row), GetString(entry.Key.ColFamily), GetString(entry.Key.ColQualifier), GetString(entry.Key.ColVisibility), GetString(entry.Value));
}
}
client.closeScanner(scanId);
Console.WriteLine();
/** Get data end **/
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
The user manual for Accumulo 1.5, is showing this code snippet and that is the same as I'm doing (but in C#): (http://accumulo.apache.org/1.5/accumulo_user_manual.html#_basic_table)
Range r = new Range(userid, userid); // single row
Scanner s = conn.createScanner("userdata", auths);
s.setRange(r);
s.fetchColumnFamily(new Text("age"));
for(Entry<Key,Value> entry : s)
System.out.println(entry.getValue().toString());
The problem is likely your range. In the Java API, you can construct a Range for a single row, with:
Range r = new Range("myRow");
In the thrift Proxy API, you can only give Keys to the Range constructor, not just RowIDs (this is an option in the Java API, also, but it is the only option in the Proxy API). Keys represent a single entry, so scanning:
R1:CF1:CQ1:CV1 -> R1:CF1:CQ1:CV1
will only ever result a scan over that one exact entry (and possibly all versions of it, if you don't have the VersioningIterator configured for the table).
So, if you want to scan all entries in row "a", you don't scan like this:
"a":null:null:null(inclusive) -> "a":null:null:null(inclusive)
Rather, you scan like this for row == "a":
"a":null:null:null(inclusive) -> "a\0":null:null:null(exclusive)
Or this, for row startsWith "a":
"a":null:null:null(inclusive) -> "b":null:null:null(exclusive)
Have you already checked that possibility here?
https://issues.apache.org/jira/browse/ACCUMULO-1189
It's fixed in Accumulo 1.5, you use 1.4, so seems worth a look.
I have written some C# code to store data into hypertable database. However I don't know how to update the data.
Below is what I have done:
Hypertable b = new Hypertable();
b.Write("1", "value1");//this line is for writing to database
b.Write("1", "value111");//this line is for updating the value whose key = "1"
and my Write function is:
public override bool Write(string key, string value)
{
try
{
using (IContext context = Context.Create(connectionString))
using (IClient client = context.CreateClient())
{
using (INamespace ns = client.OpenNamespace("Test", OpenDispositions.OpenAlways | OpenDispositions.CreateIntermediate))
{
using (ITable table = ns.OpenTable(tableName))
{
using (ITableMutator mutator = table.CreateMutator())
{
Key _key = new Key { Row = key, ColumnFamily = "vvalue" };
mutator.Set(_key, Encoding.UTF8.GetBytes(value));
}
}
}
}
return true;
}
catch (Exception e)
{
Console.WriteLine("Hypertable--Write--{0}", e.Message);
return false;
}
}
So my update is simply write again with the same key but different value. However after updating I do a read of that key and value, it is supposed to show the new key and value (key = "1" and value = "value111") but it doesn't, it just shows the old key and value (key = "1" and value = "value1")
I don't know why this happens. Any tips will be appreciated. Thanks.
You can try adding mutator.Flush() to your innermost using block, although it should be called automatically when mutator goes out of scope...