How Createx509certificate2 given certificate bytes and private key - dnx50 - x509certificate2

Basically i am using a LetsEncrypt service to get a certificate byte[] back that i can turn into a X509Certificate2 but then it is missing the private key to then use it on a SSLStream. I have the private key as a RSAParameters but can also convert it to a byte[] but i can't seem to find a way to get the 2 together in the same X509Certificate2 so i can use it for AuthenticateAsServer on a SSLStream. The methods you would use for dotnet 4 don't seems to apply for dnx50 as far as i can tell. I working example would be perfect and i want to keep the solution in dnx50 as i want to deploy this to linux and windows boxes.
Basically trying to do something similar to Convert Certificate and Private Key to .PFX programatically in C# but to just create the X509 with private key though saving would be my next task.
From what i can tell so far i think that dnx50 does not allow you to create a cetificate object and to then add a private key to it like dotnet 4 did. Instead i think i need to pass in a a file or byte[] that contains both for this to work but i don't know how to merge my 2 byte arrays together or to format them.

Finally worked out a solution for this. Not ideal but it works. Basically it uses bouncyCastle to create a pfx stream and then you can read that in to load the private key with the certificate. To do that on CoreCLR i used the nuget package Portable.BouncyCastle:1.8.1 with the following code i put in a helper class.
public X509Certificate2 CreateX509Certificate2(RSAParameters keys, byte[] certificateBytes, string friendlyName)
{
if (string.IsNullOrWhiteSpace(friendlyName))
{
friendlyName = "default";
}
var store = new Pkcs12Store();
var convertedKeys = GetRsaKeyPair(keys);
var certificate = new X509CertificateParser().ReadCertificate(certificateBytes);
store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(convertedKeys.Private), new X509CertificateEntry[] { new X509CertificateEntry(certificate)});
using (MemoryStream ms = new MemoryStream())
{
var random = new SecureRandom();
string password = random.Next().ToString() + random.Next().ToString() + random.Next().ToString();
store.Save(ms, password.ToCharArray(), random);
var cert = new X509Certificate2(ms.ToArray(), password, X509KeyStorageFlags.Exportable);
return cert;
}
}
private AsymmetricCipherKeyPair GetRsaKeyPair(
RSAParameters rp)
{
BigInteger modulus = new BigInteger(1, rp.Modulus);
BigInteger pubExp = new BigInteger(1, rp.Exponent);
RsaKeyParameters pubKey = new RsaKeyParameters(
false,
modulus,
pubExp);
RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
modulus,
pubExp,
new BigInteger(1, rp.D),
new BigInteger(1, rp.P),
new BigInteger(1, rp.Q),
new BigInteger(1, rp.DP),
new BigInteger(1, rp.DQ),
new BigInteger(1, rp.InverseQ));
return new AsymmetricCipherKeyPair(pubKey, privKey);
}

Related

Deriving device connection string from the environment

IoT modules can be created from the environment using :
ModuleClient.CreateFromEnvironmentAsync(settings)
However, there does not seem to be an equivalent method for devices. For now, I am setting the device connection string in the program to test it out, but is there a better way to read teh connection string from iotedge/config.yaml for all the edge devices deployed out there?
Methods to do so for .NET and python would be appreciated.
You can use a yaml parse library to deserialize the document, such as YamlDotNet. In fact, you can refer to YamlDocument in iot edge. But in the class, it does not provide a method to get the key value. Please refer to following code.
public class YamlDocument
{
readonly Dictionary<object, object> root;
public YamlDocument(string input)
{
var reader = new StringReader(input);
var deserializer = new Deserializer();
this.root = (Dictionary<object, object>)deserializer.Deserialize(reader);
}
public object GetKeyValue(string key)
{
if(this.root.ContainsKey(key))
{
return this.root[key];
}
foreach(var item in this.root)
{
var subItem = item.Value as Dictionary<object, object>;
if(subItem != null && subItem.ContainsKey(key))
{
return subItem[key];
}
}
return null;
}
}
And then you can get the device connection string from the config.yaml. If you use python, you can import yaml library to analysis the file.
StreamReader sr = new StreamReader(#"C:\ProgramData\iotedge\config.yaml");
var yamlString = sr.ReadToEnd();
var yamlDoc = new YamlDocument(yamlString);
var connectionString = yamlDoc.GetKeyValue("device_connection_string");
Console.WriteLine("{0}", connectionString);
To get the config file from the host, add the following to the docker deployment file. Note that the source file is config1.yaml which is the same as config.yaml except that it has read permissions for everyone not just root.
"createOptions": "{\"HostConfig\":{\"Binds\":[\"/etc/iotedge/config1.yaml:/app/copiedConfig.yaml\"]}}"
With the above line in place, the copiedConfig.yaml file can be used in the container, along with #Michael Xu's parsing code to derive teh connection string.
Long term, one may want to use the device provisioning service anyway but hope this helps for folks using device conenction strings for whatever reason..

How can i decrypt the xml file in iOS with AES/CBC/PKCS5Padding standard,in android the file has been decrypted ,all keys like salt, IV

private static Cipher getCipher(int mode) throws Exception {
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
//a random Init. Vector. just for testing
byte[] iv = "e675f725e675f725".getBytes("UTF-8");
c.init(mode, generateKey(), new IvParameterSpec(iv));
return c;
}
private static String Decrypt(String encrypted) throws Exception {
byte[] decodedValue = new Base64().decode(encrypted.getBytes("UTF-8")); // new BASE64Decoder().decodeBuffer(encrypted);
Cipher c = getCipher(Cipher.DECRYPT_MODE);
byte[] decValue = c.doFinal(decodedValue);
return new String(decValue);
}
private static Key generateKey() throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
char[] password = "3x5FBNs!".toCharArray();
byte[] salt = "S#1tS#1t".getBytes("UTF-8");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
SecretKey tmp = factory.generateSecret(spec);
byte[] encoded = tmp.getEncoded();
return new SecretKeySpec(encoded, "AES");
}
I tried to use RNCryptor but could not decrypt. Can anybody help me which library should i use because i have got the encrypted file and don't know how it has been encrypted.
In order to use RNCryptor it is best to use it on both platforms.
From a previous question it seems that the encrypted data was bytes, not Base64 encoded.
The primitives supplied by Apple Common Crypto and are part of the Security.framework. The header to use is #import <CommonCrypto/CommonCrypto.h> and you will find the interfaces you need in CommonCryptor.h and CommonKeyDerivation.h.
Make an attempt for iOS and add the code along with hex dumps of all input and output parameters and data both for the Android and iOS code.

Using Oauth tickets across several services?

I currently have a pair of OWIN-based services that each use OAuth authentication against the same set of users. I intend to isolate the authorisation server (i.e. The token endpoint) and somehow configure both of my services to accept this token. I assume this would involve some configuration of all my services to allow this token to be decrypted across all relevant services. Is this possible?
After talking with Brock Allen in the comments to the original post, I can't really guarantee this is a good/safe solution, but this is the code I ended up using. (Note: a version of this code is available as a nuget package.)
I created a IDataProtector implementation that uses AES:
internal class AesDataProtectorProvider : IDataProtector
{
// Fields
private byte[] key;
// Constructors
public AesDataProtectorProvider(string key)
{
using (var sha1 = new SHA256Managed())
{
this.key = sha1.ComputeHash(Encoding.UTF8.GetBytes(key));
}
}
// IDataProtector Methods
public byte[] Protect(byte[] data)
{
byte[] dataHash;
using (var sha = new SHA256Managed())
{
dataHash = sha.ComputeHash(data);
}
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = this.key;
aesAlg.GenerateIV();
using (var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV))
using (var msEncrypt = new MemoryStream())
{
msEncrypt.Write(aesAlg.IV, 0, 16);
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var bwEncrypt = new BinaryWriter(csEncrypt))
{
bwEncrypt.Write(dataHash);
bwEncrypt.Write(data.Length);
bwEncrypt.Write(data);
}
var protectedData = msEncrypt.ToArray();
return protectedData;
}
}
}
public byte[] Unprotect(byte[] protectedData)
{
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = this.key;
using (var msDecrypt = new MemoryStream(protectedData))
{
byte[] iv = new byte[16];
msDecrypt.Read(iv, 0, 16);
aesAlg.IV = iv;
using (var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV))
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
using (var brDecrypt = new BinaryReader(csDecrypt))
{
var signature = brDecrypt.ReadBytes(32);
var len = brDecrypt.ReadInt32();
var data = brDecrypt.ReadBytes(len);
byte[] dataHash;
using (var sha = new SHA256Managed())
{
dataHash = sha.ComputeHash(data);
}
if (!dataHash.SequenceEqual(signature))
throw new SecurityException("Signature does not match the computed hash");
return data;
}
}
}
}
}
And then used this in an ISecureDataFormat implementation like so:
public class SecureTokenFormatter : ISecureDataFormat<AuthenticationTicket>
{
// Fields
private TicketSerializer serializer;
private IDataProtector protector;
private ITextEncoder encoder;
// Constructors
public SecureTokenFormatter(string key)
{
this.serializer = new TicketSerializer();
this.protector = new AesDataProtectorProvider(key);
this.encoder = TextEncodings.Base64Url;
}
// ISecureDataFormat<AuthenticationTicket> Members
public string Protect(AuthenticationTicket ticket)
{
var ticketData = this.serializer.Serialize(ticket);
var protectedData = this.protector.Protect(ticketData);
var protectedString = this.encoder.Encode(protectedData);
return protectedString;
}
public AuthenticationTicket Unprotect(string text)
{
var protectedData = this.encoder.Decode(text);
var ticketData = this.protector.Unprotect(protectedData);
var ticket = this.serializer.Deserialize(ticketData);
return ticket;
}
}
The 'key' parameter on the constructor can then set to the same value on a number of services and they will all be able to decrypt ('unprotect') and use the ticket.
The Katana OAuth2 Authorization Server middleware wasn't really designed for this scenario (mainly because its reliance upon the machinekey for token verification).
If you're looking to centralize the token generation then you should look into an OAuth2 authorization server that's designed for this. Thinktecture AuthorizationServer is an open source server that does this: http://thinktecture.github.io/Thinktecture.AuthorizationServer/
I know this is an old question, but I had a similar use case. According to the docs, OWIN OAuth uses the machine key to protect the data. Since you control all instances, I presume that simply setting the machinekey in the web config would work.
Ref: http://msdn.microsoft.com/en-us/library/microsoft.owin.security.oauth.oauthauthorizationserveroptions(v=vs.113).aspx
You can use this nuget package https://www.nuget.org/packages/Owin.Security.AesDataProtectorProvider/
It contains extension method for IAppBuilder that allows you setup own key
appBuilder.UseAesDataProtectorProvider(key);

jclouds HP compute service stopped working for new users

I wrote code that uses jclouds' HP cloud compute service, and everything worked well.
Yesterday I opened a new account on HP, and the code failed. Getting an error about version - so I assume HP upgraded their openstack version, however I can't find documentation anywhere to what should be changed in jclodus.
This is my code
public static ComputeServiceContext createJcloudsContext(String project, String key, String secretKey ) {
ServerConfig serverConfig = ApplicationContext.get().conf().server;
ComputeServiceContext context;
Properties overrides = new Properties();
overrides.put("jclouds.keystone.credential-type", "apiAccessKeyCredentials");
context = ContextBuilder.newBuilder( serverConfig.cloudProvider.label )
.credentials( project + ":" + key, secretKey )
.overrides(overrides)
.buildView(ComputeServiceContext.class);
return context;
}
And this is the error
java.util.NoSuchElementException: no endpoints for apiType compute are of version 1.1, or version agnostic: [Service{type=compute, name=Compute, endpoints=[Endpoint{versionId=2, region=region-a.geo-1, publicURL=https://region-a.geo-1.compute.hpcloudsvc.com/v2/10050594585198, internalURL=null, adminURL=null, versionInfo=https://region-a.geo-1.compute.hpcloudsvc.com/v2/, versionList=https://region-a.geo-1.compute.hpcloudsvc.com, tenantId=10050594585198}, Endpoint{versionId=2, region=region-b.geo-1, publicURL=https://region-b.geo-1.compute.hpcloudsvc.com/v2/10050594585198, internalURL=null, adminURL=null, versionInfo=https://region-b.geo-1.compute.hpcloudsvc.com/v2/, versionList=https://region-b.geo-1.compute.hpcloudsvc.com, tenantId=10050594585198}]}]
EDIT:
Barak's answer was good for the code snippet I posted - minimal code snippet for reproduction.
It seems that afterwards I get the same error for another line. below is the full code snippet.
Here is my code
final String provider = "hpcloud-compute";
final String user = USER_VALUE;
final String key = KEY_VALUE;
Properties overrides = new Properties();
overrides.setProperty("jclouds.keystone.credential-type", "apiAccessKeyCredentials");
overrides.setProperty(Constants.PROPERTY_ENDPOINT, "https://region-b.geo-1.identity.hpcloudsvc.com:35357/v2.0/");
overrides.setProperty("jclouds.api-version", "2");
ComputeServiceContext context = ContextBuilder
.newBuilder(provider)
.credentials(user, key)
.overrides(overrides)
.buildView(ComputeServiceContext.class);
Set<? extends ComputeMetadata> computeMetadatas = context.getComputeService().listNodes();
((RestContext<NovaApi, NovaAsyncApi>)context.unwrap()).getApi().getKeyPairExtensionForZone(zone);
((RestContext<NovaApi, NovaAsyncApi>)context.unwrap()).getApi().getSecurityGroupExtensionForZone(zone);
EDIT:
Turns out, the new HP cloud does not have availability zone "az1","az2"...
Instead, I need to pass "region-b.geo-1" and it works!
Add the following override:
overrides.put("jclouds.api-version":"2")
You may want to have a look at this forum post for more details: https://cloudifysource.zendesk.com/entries/30497773-Can-we-use-cloudify-with-HP-Cloud-environment-13-5-

Getting Data from a Website using MVC 4 Web API

This is a follow-up to this post: New at MVC 4 Web API Confused about HTTPRequestMessage
Here is a summary of what I am trying to do: There is a web site that I want to interface with via MVC 4 Web API. At the site, users can log in with a user name and password, then go to a link called ‘Raw Data’ to query data from the site.
On the ‘Raw Data’ page, there is a dropdown list for ‘Device’, a text box for ‘From’ date, and a text box for ‘To’ date. Given these three parameters, the user can click the ‘Get Data’ button, and return a table of data to the page. What I have to do, is host a service on Azure that will programmatically provide values for these three parameters to the site, and return a CSV file from the site to Azure storage.
The company that hosts the site has provided documentation to programmatically interface with the site to retrieve this raw data. The document describes how requests are to be made against their cloud service. Requests must be authenticated using a custom HTTP authentication scheme. Here is how the authentication scheme works:
Calculate an MD5 hash from the user password.
Append the request line to the end of the value from step one.
Append the date header to the end of the value in step two.
Append the message body (if any) to the end of the value in step 3.
Calculate MD5 hash over the resulting value from step 4.
Append the value from step 5 to the user email using the “:” character as a delimiter.
Calculate Base64 over the value from step 6.
The code that I am going to list was done in Visual Studio 2012, C#, .NET Framework 4.5. All of the code in this post is in my 'FileDownloadController.cs' Controller class. The ‘getMd5Hash’ function takes a string, and returns an MD5 hash:
//Create MD5 Hash: Hash an input string and return the hash as a 32 character hexadecimal string.
static string getMd5Hash(string input)
{
// Create a new instance of the MD5CryptoServiceProvider object.
MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
This function takes a string, and returns BASE64:
//Convert to Base64
static string EncodeTo64(string input)
{
byte[] str1Byte = System.Text.Encoding.ASCII.GetBytes(input);
String plaintext = Convert.ToBase64String(str1Byte);
return plaintext;
}
The next function creates an HTTPClient, makes an HTTPRequestMessage, and returns the authorization. Note: The following is the URI that was returned from Fiddler when data was returned from the ‘Raw Data’ page: GET /rawdata/exportRawDataFromAPI/?devid=3188&fromDate=01-24-2013&toDate=01-25-2013 HTTP/1.1
Let me first walk through what is happening with this function:
The ‘WebSiteAuthorization’ function takes a ‘deviceID’, a ‘fromDate’, a ‘toDate’ and a ‘password’.
Next, I have three variables declared. I’m not clear on whether or not I need a ‘message body’, but I have a generic version of this set up. The other two variables hold the beginning and end of the URI.
I have a variable named ‘dateHeader’, which holds the data header.
Next, I attempt to create an HTTPClient, assign the URI with parameters to it, and then assign ‘application/json’ as the media type. I’m still not very clear on how this should be structured.
In the next step, the authorization is created, per the requirements of the API documentation, and then the result is returned.
public static string WebSiteAuthorization(Int32 deviceid, string fromDate, string toDate, string email, string password)
{
var messagebody = "messagebody"; // TODO: ??????????? Message body
var uriAddress = "GET/rawdata/exportRawDataFromAPI/?devid=";
var uriAddressSuffix = "HTTP/1.1";
//create a date header
DateTime dateHeader = DateTime.Today;
dateHeader.ToUniversalTime();
//create the HttpClient, and its BaseAddress
HttpClient ServiceHttpClient = new HttpClient();
ServiceHttpClient.BaseAddress = new Uri(uriAddress + deviceid.ToString() + " fromDate" + fromDate.ToString() + " toDate" + toDate.ToString() + uriAddressSuffix);
ServiceHttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//create the authorization string
string authorizationString = getMd5Hash(password);
authorizationString = authorizationString + ServiceHttpClient + dateHeader + messagebody;
authorizationString = email + getMd5Hash(authorizationString);
authorizationString = EncodeTo64(authorizationString);
return authorizationString;
}
I haven’t tested this on Azure yet. I haven't completed the code that gets the file. One thing I know I need to do is to determine the correct way to create an HttpRequestMessage and use HttpClient to send it. In the documentation that I've read, and the examples that I've looked at, the following code fragments appear to be possible approaches to this:
Var serverAddress = http://my.website.com/;
//Create the http client, and give it the ‘serverAddress’:
Using(var httpClient = new HttpClient()
{BaseAddress = new Uri(serverAddress)))
Var requestMessage = new HttpRequestMessage();
Var objectcontent = requestMessage.CreateContent(base64Message, MediaTypeHeaderValue.Parse (“application/json”)
or----
var formatters = new MediaTypeFormatter[] { new jsonMediaTypeFormatter() };
HttpRequestMessage<string> request = new HttpRequestMessage<string>
("something", HttpMethod.Post, new Uri("http://my.website.com/"), formatters);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var httpClient = new HttpClient();
var response = httpClient.SendAsync(request);
or------
Client = new HttpClient();
var request = new HttpRequestMessage
{
RequestUri = "http://my.website.com/",
Method = HttpMethod.Post,
Content = new StringContent("ur message")
};
I'm not sure which approach to take with this part of the code.
Thank you for your help.
Read this step by step tutorial to understand the basic.

Resources