I have written an input form (in ServiceNow) for admins to request a new certificate via a Cert Authority integration. However prior to submission i want to validate the Certificate Signing request has the correct headers and a keylength of 2048.
Example of CSR:
-----BEGIN CERTIFICATE REQUEST-----
MIICpTCCAY0CAQAwYDEqMCgGCSqGSIb3DQEJARYbamFtZXN0b21saW5zb25AbmJu
Y28uY29tLmF1MSUwIwYDVQQDDBxTZXJ2aWNlTm93LlRlc3QuSnVseTIxLkxvY2Fs
MQswCQYDVQQGEwJBVTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKpd
VbZG3Ph+UdiOYh+zFqH6pIavANGytWcvEnloG/DboW+JxpWQBqmZqvOZgWnPyC06
wS4f/YpElLFX83/+jLc6Gt3B/QDgfxhGaVnurDx56RvTM1LQVfBZJ3l+OYUmAof+
YB25aRhKQ4krWvXGMUujoi5QSl9yNZlAIzgpjgJ7cRHcbUhlOdcQVz/WnC2dcWB3
H/vLPIzciODOrzwIq1lSJ3OkdOJJ23Ifu19e9ySJsWYoC28THm6Ub8Z9gHHlPTfO
im5UxZFBZjLkx/YphQNNqcMxFMCO/CDo1bZlggws61O2liPzC8LpGwkroYIxngoQ
5rbvm/uyG/HelAFZYT0CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCouy3b62xV
Bu4Scd38HMgtaTCHOndutsuwNnYF6SpxdSTYYMVQIa+gHy3N4vpQ+lNboPlOhsQd
58Jt9iwnmYCR32d36FVmsIpu5xAwweQUBK5v/GIPx5yjY0k8bTFC3vJUsIxbClwC
UtUE5p7p+Ulm+4olk/+VYeKtvE+l+e89NQ4sBlOE5JVSulRsxLjRfQscvj/0Ln/7
7iZQxfgL/Vv1UUBiLfTEmfSyu5i7IomoAUBSJ9xipbh5OWolqHzIBmpQY504Es3X
Ojs9d6KwyCSu5S2yUoj98C+OidqkHXDSfwWQSCfWn1vCuTFQlFS5viYK2pzIjozE
71owCWT8RpGd
-----END CERTIFICATE REQUEST-----
I plan to write a quick client side script to validate the input, but i'm a little stumped on the syntax. Any help appreciated.
This will be very difficult to do up...
Checking the CSR headers is relatively straight forward... you can do something like the following in an onSubmit script
var totalString = g_form.getValue('fieldName').trim();
var headerString = totalString.slice(0, 35);
var encodedCertString = totalString.substring(35, totalString.length - 33);
var footerString = totalString.slice(totalString.length - 33);
var validCert = true;
validCert &= (headerString == '-----BEGIN CERTIFICATE REQUEST-----');
validCert &= (footerString == '-----END CERTIFICATE REQUEST-----');
if(!validCert){
g_form.addErrorMessage('CSR in field missing correct headers');
return false;
}
Where things get "interesting" is that what is between the headers and footer of the CSR is a Base64 encoded PKCS10 binary block of data. Writing a function to deal with binary data is generally beyond what you will want to do in a client side function... the public key itself is merely a portion of that PCKS10 binary package.. not the whole.. so there is no easy way to "decode" it to iterate through the raw binary bites to find the actual key and measure its bit length. Have a look at the PCKS10 binary package format here: https://en.wikipedia.org/wiki/Certificate_signing_request
Most folks that have online CSR decoders actually pass the input to OpenSSL and have it parse the request and report on all of the data that makes it up... For instance: https://redkestrel.co.uk/products/decoder/. You could do something similar but doing so would require a hackish/creative use of a custom MID Server script that you could call using a custom probe... Again.. not something that you would want to mess with within the bounds of a ServiceNow client script.
I am using RoR for server side and sending some encryption data to JS Client side. For ROR I am using OpenSSl encryption technique.
`c= OpenSSL::Cipher::Cipher.new('aes-256-cbc')
c = cipher.encrypt
c.key = Digest::SHA256.digest(key)
Base64.strict_encode64(c.update(value.to_s) + c.final)
`
This is my code for encryption in ROR
`var cipherParams:any = CryptoJS.lib.CipherParams.create({
ciphertext: CryptoJS.enc.Base64.parse(encrypted_data)
});
var digest = CryptoJS.SHA256(key.toString(CryptoJS.enc.Utf8));
let bytes = CryptoJS.AES.decrypt(cipherParams, digest, {iv: iv});
bytes.toString(CryptoJS.enc.Utf8);
`
This is my JS decryption logic
when I am encrypting some key value pair data from server I am not able to decrypt it. I am getting this error
MalFormed Utf8
but when I am trying to decrypt single value like: "5678" I am getting correct value.If I changed CryptoJS.enc.Utf8 to CryptoJS.enc.Latin1 I am getting some unreadable value but error is not showing.
I think converting it to UTF8 is giving problem.But why?
I have tried many solutions. I am using proper key and digest and IV, I have checked it multiple times, and I am also sending proper string keys and values.
My team must share data between a localnet html/js app, and a server in the same net listening on a websocket.
The first idea was to simply send variables to the server with get
http://192.168.1.100:8080/var=hello
It's simple and works, but we must add a security level to the data exchange, encrypting all in Aes and then hexing the result to send it as plain string.
The best solution that we found is Crypto-JS https://code.google.com/p/crypto-js/
We are able to follow the examples and encrypting/decrypting data inside the same js block, but are unable to decrypt the data on another software.
we do:
var text = "Message";
var password = "Secret Passphrase";
var encrypted = CryptoJS.AES.encrypt(text, password);
var EnText = encrypted.ciphertext; //returns the hexed/encrypted text
var Key = encrypted.key;
It doesn't work with the c# code running on the server, so we tried an online decrypting tool http://aes.online-domain-tools.com/ passing both the password and the Key, but similarly returns unreadable text
JS generated value for reference
EnText: 5768c9b4d75e0cc32b610d9e6f518c36
Key: 005e316192f5162f7fd104ce2c9fe91de6c6f2977849dcd5878226022a7073be
What are we missing?
Ok i got it, the text is in hexadecimal.
Try decyphering it there:
http://www.unit-conversion.info/texttools/hexadecimal/
I have spent several days researching and working on a solution for uploading/downloading byte[]’s. I am close, but have one remaining issue that appears to be in my AngularJS code block.
There is a similar question on SO, but it has no responses. See https://stackoverflow.com/questions/23849665/web-api-accept-and-post-byte-array
Here is some background information to set the context before I state my problem.
I am attempting to create a general purpose client/server interface to upload and download byte[]’s, which are used as part of a proprietary server database.
I am using TypeScript, AngularJS, JavaScript, and Bootstrap CSS on the client to create a single page app (SPA).
I am using ASP.NET Web API/C# on the server.
The SPA is being developed to replace an existing product that was developed in Silverlight so it is constrained to existing system requirements. The SPA also needs to target a broad range of devices (mobile to desktop) and major OSs.
With the help of several online resources (listed below), I have gotten most of my code working. I am using an asynchronous multimedia formatter for byte[]’s from the Byte Rot link below.
http://byterot.blogspot.com/2012/04/aspnet-web-api-series-part-5.html
Returning binary file from controller in ASP.NET Web API
I am using a jpeg converted to a Uint8Array as my test case on the client.
The actual system byte arrays will contain mixed content compacted into predefined data packets. However, I need to be able to handle any valid byte array so an image is a valid test case.
The data is transmitted to the server correctly using the client and server code shown below AND the Byte Rot Formatter (NOT shown but available on their website).
I have verified that the jpeg is received properly on the server as a byte[] along with the string parameter metadata.
I have used Fiddler to verify that the correct response is sent back to the client.
The size is correct
The image is viewable in Fiddler.
My problem is that the server response in the Angular client code shown below is not correct.
By incorrect, I mean the wrong size (~10K versus ~27.5K) and it is not recognized as a valid value for the UintArray constructor. Visual Studio shows JFIF when I place the cursor over the returned “response” shown in the client code below, but there is no other visible indicator of the content.
/********************** Server Code ************************/
Added missing item to code after [FromBody]byte[]
public class ItemUploadController : ApiController{
[AcceptVerbs("Post")]
public HttpResponseMessage Upload(string var1, string var2, [FromBody]byte[] item){
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new MemoryStream(item);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return result;
}
}
/***************** Example Client Code ********************/
The only thing that I have omitted from the code are the actual variable parameters.
$http({
url: 'api/ItemUpload/Upload',
method: 'POST',
headers: { 'Content-Type': 'application/octet-stream' },// Added per Byte Rot blog...
params: {
// Other params here, including string metadata about uploads
var1: var1,
var2: var2
},
data: new Uint8Array(item),
// arrybuffer must be lowecase. Once changed, it fixed my problem.
responseType: 'arraybuffer',// Added per http://www.html5rocks.com/en/tutorials/file/xhr2/
transformRequest: [],
})
.success((response, status) => {
if (status === 200) {
// The response variable length is about 10K, whereas the correct Fiddler size is ~27.5K.
// The error that I receive here is that the constructor argument in invalid.
// My guess is that I am doing something incorrectly with the AngularJS code, but I
// have implemented everything that I have read about. Any thoughts???
var unsigned8Int = new Uint8Array(response);
// For the test case, I want to convert the byte array back to a base64 encoded string
// before verifying with the original source that was used to generate the byte[] upload.
var b64Encoded = btoa(String.fromCharCode.apply(null, unsigned8Int));
callback(b64Encoded);
}
})
.error((data, status) => {
console.log('[ERROR] Status Code:' + status);
});
/****************************************************************/
Any help or suggestions would be greatly appreciated.
Thanks...
Edited to include more diagnostic data
First, I used the angular.isArray function to determine that the response value is NOT an array, which I think it should be.
Second, I used the following code to interrogate the response, which appears to be an invisible string. The leading characters do not seem to correspond to any valid sequence in the image byte array code.
var buffer = new ArrayBuffer(response.length);
var data = new Uint8Array(buffer);
var len = data.length, i;
for (i = 0; i < len; i++) {
data[i] = response[i].charCodeAt(0);
}
Experiment Results
I ran an experiment by creating byte array values from 0 - 255 on the server, which I downloaded. The AngularJS client received the first 128 bytes correctly (i.e., 0,1,...,126,127), but the remaining values were 65535 in Internet Explorer 11, and 65533 in Chrome and Firefox. Fiddler shows that 256 values were sent over the network, but there are only 217 characters received in the AngularJS client code. If I only use 0-127 as the server values, everything seems to work. I have no idea what can cause this, but the client response seems more in line with signed bytes, which I do not think is possible.
Fiddler Hex data from the server shows 256 bytes with the values ranging from 00,01,...,EF,FF, which is correct. As I mentioned earlier, I can return an image and view it properly in Fiddler, so the Web API server interface works for both POST and GET.
I am trying vanilla XMLHttpRequest to see I can get that working outside of the AngularJS environment.
XMLHttpRequest Testing Update
I have been able to confirm that vanilla XMLHttpRequest works with the server for the GET and is able to return the correct byte codes and the test image.
The good news is that I can hack around AngularJS to get my system working, but the bad news is that I do not like doing this. I would prefer to stay with Angular for all my client-side server communication.
I am going to open up a separate issue on Stack Overflow that only deals with the GET byte[] issues that I am have with AngularJS. If I can get a resolution, I will update this issue with the solution for historical purposes to help others.
Update
Eric Eslinger on Google Groups sent me a small code segment highlighting that responseType should be "arraybuffer", all lower case. I updated the code block above to show the lowercase value and added a note.
Thanks...
I finally received a response from Eric Eslinger on Google Group. He pointed out that he uses
$http.get('http://example.com/bindata.jpg', {responseType: 'arraybuffer'}).
He mentioned that the camelcase was probably significant, which it is. Changed one character and the entire flow is working now.
All credit goes to Eric Eslinger.
I'm trying to read from an encfs filesystem with JavaScript but don't get the correct use of it. I use the CryptoJS library.
The .ecnfs6.xml with standard settings and password 123456:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="9">
<cfg class_id="0" tracking_level="0" version="20">
<version>20100713</version>
<creator>EncFS 1.7.4</creator>
<cipherAlg class_id="1" tracking_level="0" version="0">
<name>ssl/aes</name>
<major>3</major>
<minor>0</minor>
</cipherAlg>
<nameAlg>
<name>nameio/block</name>
<major>3</major>
<minor>0</minor>
</nameAlg>
<keySize>192</keySize>
<blockSize>1024</blockSize>
<uniqueIV>1</uniqueIV>
<chainedNameIV>1</chainedNameIV>
<externalIVChaining>0</externalIVChaining>
<blockMACBytes>0</blockMACBytes>
<blockMACRandBytes>0</blockMACRandBytes>
<allowHoles>1</allowHoles>
<encodedKeySize>44</encodedKeySize>
<encodedKeyData>
A2MxizkB27kOot67DqX/ftXoAiO0P8ORF4BqbKnbMeHuIusJl5y36Qy8o8w=
</encodedKeyData>
<saltLen>20</saltLen>
<saltData>
z59o4aHs2QaKGdoEMEigtqSkXyw=
</saltData>
<kdfIterations>97742</kdfIterations>
<desiredKDFDuration>500</desiredKDFDuration>
</cfg>
</boost_serialization>
I created a file with name and content "test" and tried to decrypt that wit no success:
var data = "Q75cZB2ok,JdXDqvWh8HbwHI"; // filename
var key = "123456";
var salt = "z59o4aHs2QaKGdoEMEigtqSkXyw=";
data = CryptoJS.enc.Base64.parse(data);
salt = CryptoJS.enc.Base64.parse(salt);
var cipher = CryptoJS.AES.decrypt(data, key, {keySize: 192/32});
The way EncFS works is that it creates a volume key (192 bits according to your config) and encrypts the volume key using another key which is derived from the user's password (the algorithm used for deriving the password key is called PBKDF2 - Password-Based Key Derivation Function).
Given that config file, what you have to do is:
Take the user's password, input into PBKDF2 computation along with the salt and iteration count (both present in the config file) to get back the password key.
Using the password key, decrypt the volume key (AES stream decryption) from the encodedKeyData field of the config
Once you have the volume key you can use it to decrypt filenames as well as file contents.
For examples of how this is done, you can take a look at the following library which I wrote in Java:
https://github.com/mrpdaemon/encfs-java
Current JavaScript implementations are far too slow to generate a
PBKDF2 with more than 1000 - 2000 (not noticeably delayed) to
10000 (noticeable delay) iterations. An iteration count like in your
example 97742 would take hours to finish...
Update: Only when using CryptoJS apparently: see JSPerf and JSFiddle for PBKDF2.