I have run Checkmarx scan on my application . The scan report reports the following on my piece of code.
"Inadequate encryption strength - The application uses a weak cryptographic algorithm, getPrivate() to protect sensitive personal information password"
public String sign(String text) {
try {
KeyPair keyPair = this.getKeyPair();
Signature privateSignature = Signature.getInstance("SHA1withRSA");
privateSignature.initSign(**keyPair.getPrivate()**);
privateSignature.update(text.getBytes(UTF_8));
byte[] signature = privateSignature.sign();
return Base64.getEncoder().encodeToString(signature);
} catch (Exception exp) {
}
}
public KeyPair getKeyPair()
throws Exception {
Key key = this.keyStore.getKey(ALIAS, **this.password.toCharArray()**);
Certificate cert = this.keyStore.getCertificate(ALIAS);
PublicKey publicKey = cert.getPublicKey();
return new KeyPair(publicKey, (PrivateKey) key);
}
Please help me in resolving this issue.
Related
I'm getting an error when verifying an Azure AD generated token. This is the current setup:
I have a token which can be pasted on https://jwt.io, and I can see in the right panel the correct claims. I assume the token is correctly formatted. I can also see in the headers that kid = piVlloQDSMKxh1m2ygqGSVdgFpA and alg: RS256. I set correctly the algo type to RS256 for verification.
I went to https://login.microsoftonline.com/common/discovery/keys to find the public key, and found the same kid = piVlloQDSMKxh1m2ygqGSVdgFpA. So I copied the corresponds public key (the string in the x5c field) and wrapped it into the correct strings to make it PKCS#8. compatible:
-----BEGIN CERTIFICATE-----
MIIDBTCCAe2gAwIBAgIQMCJcgWf4l5xPpeoEwB7DKDANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE5MTExNTAwMDAwMFoXDTI0MTExNDAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANF4YcKZhKTfowwWqZ84RW7bxFNgaSy3Gi85V5uJpU9jMCmZV0VFGptryNFEQ1GESmmuDutgQlkkhjr9ixkOrTA+aFPg6pLn+OG6NYS7nyKgAC1MprLH0bq06y3dH6lQPWQhd3wPP+8UIua9+9JuIfhu9Xs/HhN5cYlT5cEniV0aWuUMxgPAKcG1xolfupYhlOHjFwVN/QOaxcuk3YqGguD+sZ7PiHcJSzFnTkdvD+DtMoW1U6nDf5FuDeAEKJ7JQf7RjiRoViYxZHKrEPHG4iZ+kOhV6DQA16ISTt7ALXVB8gTTF3OvItubk2E3v6sgirgtvdE5Mkd4MTJcO67bgdUCAwEAAaMhMB8wHQYDVR0OBBYEFEXiTeLGkA2LgAjQOrT2KChpgwCgMA0GCSqGSIb3DQEBCwUAA4IBAQA6GqtYZDQzym0yxfL2NnlSbJP/lLhSQOqbPBdN6DWQ/3duk+e08Ix5qy63hzW+qQR0PAkFEcooL5+bdheS66tFJpVejEcqCSKUVvwOUe6GY/ju752dlB7anBB9An362khehCxqydYNS5Igl0rtcP7dKC3ZBn1m2B9ULsyx46iNpfHQHHv9NKU2vVq2CtNc95CFktwjUwlyWMgbfI/DzPX/cC6KnglqsuVVBO7+jIaBmi0XGqudooZkqgIrvnfNMM13Gy78TUNHsCiAQEwZ/L17yNbzotNGxAoPfuXldbD52MQNOsA7WhH+j8qFWY6gZzTN4NpVtuW4m04TCEFexnTz
-----END CERTIFICATE-----
In case it's not visible above, there is a \n after -----BEGIN CERTIFICATE----- and before -----END CERTIFICATE-----
That public key got copied in the public key part of it, and in my code it's the public RSA key.
I also tried formatting using PKCS#1, I didn't get more success
It keeps being invalid. Not even expired, clearly invalid, both on jwt.io and in my code.
Assuming the token is correct, is my methodology correct? I found different tutorials preparing the .pem differently. If my token is incorrect, how can I check that aside of getting claims from it?
You need to generate the public key from modulus and exponent.
You can get them from https://login.microsoftonline.com/{tenantId_or_commom}/discovery/v2.0/keys
Here is a java sample for your reference:
public static PublicKey getPublicKey(String encodedModulus, String encodedExponent) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] modulus = Base64.getUrlDecoder().decode(encodedModulus);
byte[] exponent = Base64.getUrlDecoder().decode(encodedExponent);
StringBuilder sb = new StringBuilder();
for (byte b : modulus) {
sb.append(String.format("%02x", b));
}
String sm = sb.toString();
sb = new StringBuilder();
for (byte b : exponent) {
sb.append(String.format("%02x", b));
}
String se = sb.toString();
BigInteger bm = new BigInteger(sm,16);
BigInteger be = new BigInteger(se,16);
KeyFactory rsa = KeyFactory.getInstance("RSA");
PublicKey publicKey = rsa.generatePublic(new RSAPublicKeySpec(bm, be));
return publicKey;
}
public static void main(String[] args) throws Exception {
String modulus = "0XhhwpmEpN-jDBapnzhFbtvEU2BpLLcaLzlXm4mlT2MwKZlXRUUam2vI0URDUYRKaa4O62BCWSSGOv2LGQ6tMD5oU-Dqkuf44bo1hLufIqAALUymssfRurTrLd0fqVA9ZCF3fA8_7xQi5r370m4h-G71ez8eE3lxiVPlwSeJXRpa5QzGA8ApwbXGiV-6liGU4eMXBU39A5rFy6TdioaC4P6xns-IdwlLMWdOR28P4O0yhbVTqcN_kW4N4AQonslB_tGOJGhWJjFkcqsQ8cbiJn6Q6FXoNADXohJO3sAtdUHyBNMXc68i25uTYTe_qyCKuC290TkyR3gxMlw7rtuB1Q";
String exponent = "AQAB";
byte[] bytes = getPublicKey(modulus, exponent).getEncoded();
String encodedString = new String(Base64.getEncoder().encode(bytes));
System.out.println("-----BEGIN PUBLIC KEY-----");
System.out.println(encodedString);
System.out.println("-----END PUBLIC KEY-----");
System.out.println();
}
You will get some outputs as following:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0XhhwpmEpN+jDBapnzhFbtvEU2BpLLcaLzlXm4mlT2MwKZlXRUUam2vI0URDUYRKaa4O62BCWSSGOv2LGQ6tMD5oU+Dqkuf44bo1hLufIqAALUymssfRurTrLd0fqVA9ZCF3fA8/7xQi5r370m4h+G71ez8eE3lxiVPlwSeJXRpa5QzGA8ApwbXGiV+6liGU4eMXBU39A5rFy6TdioaC4P6xns+IdwlLMWdOR28P4O0yhbVTqcN/kW4N4AQonslB/tGOJGhWJjFkcqsQ8cbiJn6Q6FXoNADXohJO3sAtdUHyBNMXc68i25uTYTe/qyCKuC290TkyR3gxMlw7rtuB1QIDAQAB
-----END PUBLIC KEY-----
And then you can use it in jwt.io:
I keep getting an "invalid_grant" error when I try to use the DocuSign sdk to generate a JWT user token, and I can't figure out where I'm going wrong here...
public OAuthToken GetJwtToken(string userId)
{
try
{
var client = new ApiClient();
var authToken = client.RequestJWTUserToken
(
IntegrationKey,
userId,
BaseUrl,
Encoding.UTF8.GetBytes(PrivateKey),
1,
new List<string> { "signature", "impersonation" }
);
return authToken;
}
catch (ApiException e)
{
var msg = e.Message;
}
return null;
}
And the values:
<add key="IntegrationKey" value="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
<add key="PrivateKey" value="-----BEGIN RSA PRIVATE KEY-----\r\n\xxxxxxxxxxxx\r\n-----END RSA PRIVATE KEY-----" />
<add key="BaseUrl" value="account-d.docusign.com" />
I have a feeling it has something to do with the way the private key is coming in. I have it stored in the web config with \r\n for each new line, but if I try to just read it from the config file and pass it in, this line in the CreateRSAKeyFromPem() method throws a System.IO.IOException saying "-----END RSA PRIVATE KEY not found" unless I do a '.Replace("\r\n", "\r\n")' on the private key string:
object result = pemReader.ReadObject();
I've looked at every thread I can find, copied the example code for this, and quadruple checked all of my values. I have no idea why this won't work.
Edit: I pasted the assertion string that the code is sending in the request into https://jwt.io/ and I was able to verify that the decoded data is correct and the signature is verified after pasting in my public and private keys. I'm not sure why this wouldn't be working after checking all of that.
Edit 2: This is how I'm storing my RSA private key:
<add key="DocuSign:PrivateKey" value="-----BEGIN RSA PRIVATE KEY-----\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\nxxxxxxx\r\n-----END RSA PRIVATE KEY-----" />
and I'm retrieving it like this (System.IO throws this error if I try to grab the value without that Replace in there: "-----END RSA PRIVATE KEY not found")
public static string PrivateKey { get { return ConfigurationManager.AppSettings["DocuSign:PrivateKey"].Replace("\\r\\n", "\r\n"); } }
I ended up having to delete my RSA keypair for my app and generating a new one. The new key worked. I'm not sure why the old one didn't, but this resolved it at least.
One of our partner is sending signed SMIME messages to us using NOSPAMPROXY. Everything works fine except the one using SHA256WITHRSA . Bouncy castle is saying that the signature verification failed. Please see the code segment below,
public static boolean verifySignature(SMIMESigned s, X509Certificate myCert) throws Exception {
SignerInformationStore signers = s.getSignerInfos();
Collection c = signers.getSigners();
for (Iterator it = c.iterator(); it.hasNext(); ) {
try {
SignerInformation signer = (SignerInformation) it.next();
final SignerInformationVerifier verifier = new JcaSimpleSignerInfoVerifierBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build(
myCert);
if (signer.verify(verifier)) {
return true;
}
} catch (CMSException ex) {
Tracer.debug(ex);
}
}
return false;
}
myCert is the certificate we are giving for verify. Any help is appreciated .
I am trying to use Jose (https://bitbucket.org/b_c/jose4j/wiki/Home) to generate a signed JsonWebToken. I am running into a problem creating the RsaKeyPairs that I need to use in the signature of the token.
This is the code I am using to generate the public/private Keys and I need to turn this to String so I can store them in the database and then retrieve them.
WebKeyManager wkm = null;
Object obj;
EncryptionKey encKey = null;
RsaJsonWebKey rsaJsonWebKey = null;
try
{
wkm = new WebKeyManager();
int keySize = 512;
// Initialize KeyPairGenerator.
SecureRandom random = SecureRandom.getInstanceStrong(); //cryptographically strong random number generator
// Generate an RSA key pair, which will be used for signing and verification of the JWT, wrapped in a JWK
rsaJsonWebKey = RsaJwkGenerator.generateJwk(keySize, random.getProvider().getName(),random);
// Give the JWK a Key ID (kid), which is just the polite thing to do
rsaJsonWebKey.setKeyId(""+System.currentTimeMillis());
String json = rsaJsonWebKey.toJson(OutputControlLevel.INCLUDE_PRIVATE);
}
catch (Exception e)
{
e.printStackTrace();
}
The Problem I am Encountering is when I do rsaJsonWebKey.toJson(OutputControlLevel.INCLUDE_PRIVATE)
I get this error:
java.lang.ClassCastException: sun.security.mscapi.RSAPrivateKey cannot be cast to java.security.interfaces.RSAPrivateKey
at org.jose4j.jwk.RsaJsonWebKey.getRsaPrivateKey(RsaJsonWebKey.java:123)
at org.jose4j.jwk.RsaJsonWebKey.fillPrivateTypeSpecificParams(RsaJsonWebKey.java:135)
at org.jose4j.jwk.PublicJsonWebKey.fillTypeSpecificParams(PublicJsonWebKey.java:122)
at org.jose4j.jwk.JsonWebKey.toParams(JsonWebKey.java:166)
at org.jose4j.jwk.JsonWebKey.toJson(JsonWebKey.java:178)
I tried to debug the code in Jose and the error is in PublicJsonWebKey class this line:
protected void fillPrivateTypeSpecificParams(Map<String,Object> params)
{
RSAPrivateKey rsaPrivateKey = getRsaPrivateKey();
rsaPrivateKey is java.security.interfaces.RSAPrivateKey while getRsaPrivateKey() returns org.jose4j.jwk.RsaJsonWebKey
What am I doing wrong?
My requirement is to generate KeyPairs, store them in the database in varchar type field or something similar and then whenever needed, I can retrieve the String from the database, convert it back to private/public keys and use them to sign the token?
After some research, I found out that if I create the keys using this constructor
rsaJsonWebKey = RsaJwkGenerator.generateJwk(keySize);
then I don't get the error.
Reaching out to for your help / support.
We have a requirement to Encrypt the data in table storage and Decrypt the data while pulling it from table storage. Tried with the sample application found in https://github.com/Azure/azure-storage-net.
In the sample application Encryption and Decyption is happening in same method. In my case it rasing error in "Decrypt" function and the error is - "Error occurred while decoding OAEP padding" But we need to two separate functions. Even we need to pull the data through Table Query.
Please find below is my code -
const string DemoTable = "demotable";
static void Main(string[] args)
{
RsaKey key = new RsaKey("mydemokey");
string partitionid = "mydemoid123456";
EncryptData(partitionid, key);
DecryptData(partitionid, key);
}
public static void EncryptData(string partitionid, RsaKey rsakey)
{
CloudStorageAccount storageAccount = EncryptionShared.Utility.CreateStorageAccountFromConnectionString();
CloudTableClient client = storageAccount.CreateCloudTableClient();
CloudTable table = client.GetTableReference(DemoTable);
try
{
table.Create();
EncryptedEntity ent = new EncryptedEntity() { PartitionKey = partitionid, RowKey = "DemoKey1" };
ent.Populate();
TableRequestOptions insertOptions = new TableRequestOptions()
{
EncryptionPolicy = new TableEncryptionPolicy(rsakey, null)
};
table.Execute(TableOperation.Insert(ent), insertOptions, null);
}
catch (Exception ex)
{
Console.Write(ex.Message);
}
}
public static void DecryptData(string partitionid, RsaKey rsakey)
{
CloudStorageAccount storageAccount = EncryptionShared.Utility.CreateStorageAccountFromConnectionString();
CloudTableClient client = storageAccount.CreateCloudTableClient();
CloudTable table = client.GetTableReference(DemoTable);
try
{
EncryptedEntity ent = new EncryptedEntity() { PartitionKey = partitionid, RowKey = "DemoKey1" };
ent.Populate();
LocalResolver resolver = new LocalResolver();
resolver.Add(rsakey);
TableRequestOptions retrieveOptions = new TableRequestOptions()
{
EncryptionPolicy = new TableEncryptionPolicy(null, resolver)
};
TableOperation operation = TableOperation.Retrieve(ent.PartitionKey, ent.RowKey);
TableResult result = table.Execute(operation, retrieveOptions, null);
}
catch (Exception ex)
{
Console.Write(ex.Message);
}
}
}
Am I doing any mistake or any other option available to Encypt and Decrypt the data in Table Storage (including partitionkey).
Decrypt Error
Thanks in advance for your help.
Best Regards,
Debasis
According to your codes, I found you add the rsakey to the LocalResolver object in the DecryptData method.
As far as I know, the raskey is a one-time-use symmetric key and its value is not same after generated.
If you don’t use the right raskey(generated when you update the table entity), you couldn’t get the right result from the table storage.
More details about how the client-side encryption worked you could refer to follow step and link:
Encryption via the envelope technique works in the following way:
The Azure storage client library generates a content encryption key (CEK), which is a one-time-use symmetric key.
User data is encrypted using this CEK.
The CEK is then wrapped (encrypted) using the key encryption key (KEK). The KEK is identified by a key identifier and can be an asymmetric key pair or a symmetric key and can be managed locally or stored in Azure Key Vaults.
The storage client library itself never has access to KEK. The library invokes the key wrapping algorithm that is provided by Key Vault. Users can choose to use custom providers for key wrapping/unwrapping if desired.
The encrypted data is then uploaded to the Azure Storage service. The wrapped key along with some additional encryption metadata is either stored as metadata (on a blob) or interpolated with the encrypted data (queue messages and table entities).
Decryption via the envelope technique works in the following way:
The client library assumes that the user is managing the key encryption key (KEK) either locally or in Azure Key Vaults. The user does not need to know the specific key that was used for encryption. Instead, a key resolver which resolves different key identifiers to keys can be set up and used.
The client library downloads the encrypted data along with any encryption material that is stored on the service.
The wrapped content encryption key (CEK) is then unwrapped (decrypted) using the key encryption key (KEK). Here again, the client library does not have access to KEK. It simply invokes the custom or Key Vault provider’s unwrapping algorithm.
The content encryption key (CEK) is then used to decrypt the encrypted user data.
Link:https://learn.microsoft.com/en-us/azure/storage/storage-client-side-encryption
I suggest you could use below codes to get the right result.
class Program
{
const string DemoTable = "demotable";
const string ConnectionString = "yourconnectionstring";
// For retrieves, a resolver can be set up that will help pick the key based on the key id.
static LocalResolver resolver = new LocalResolver();
static void Main(string[] args)
{
RsaKey key = new RsaKey("mydemokey");
string partitionid = "mydemoid123456";
EncryptData(partitionid, key);
DecryptData(partitionid, key);
}
public static void EncryptData(string partitionid, RsaKey rsakey)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConnectionString);
CloudTableClient client = storageAccount.CreateCloudTableClient();
CloudTable table = client.GetTableReference(DemoTable);
try
{
table.CreateIfNotExists();
EncryptedEntity ent = new EncryptedEntity() { PartitionKey = partitionid, RowKey = "DemoKey1" ,Test = "aaaa" };
//ent.Populate();
TableRequestOptions insertOptions = new TableRequestOptions()
{
EncryptionPolicy = new TableEncryptionPolicy(rsakey, null)
};
resolver.Add(rsakey);
table.Execute(TableOperation.Insert(ent), insertOptions, null);
}
catch (Exception ex)
{
Console.Write(ex.Message);
}
}
public static void DecryptData(string partitionid, RsaKey rsakey)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConnectionString);
CloudTableClient client = storageAccount.CreateCloudTableClient();
CloudTable table = client.GetTableReference(DemoTable);
try
{
EncryptedEntity ent = new EncryptedEntity() { PartitionKey = partitionid, RowKey = "DemoKey1" };
//ent.Populate();
TableRequestOptions retrieveOptions = new TableRequestOptions()
{
EncryptionPolicy = new TableEncryptionPolicy(null, resolver)
};
TableOperation operation = TableOperation.Retrieve(ent.PartitionKey, ent.RowKey);
TableResult result = table.Execute(operation, retrieveOptions, null);
}
catch (Exception ex)
{
Console.Write(ex.Message);
}
}
}
Result:
Besides, the example above stored the key value in the local, normally we will use the Azure Key Vault service to store key.
More details, you could refer to follow link:
What is Azure Key Vault?
Encrypt and decrypt in Microsoft Azure Storage using Azure Key Vault