I have existing ap.net c# website is working with mysql database. now i am planning to create mobile app for that website for that API needs to be ready.
I am creating an API into PHP Laravel Framework. for RegistrationAPI needs to generate password.
Asp.net using its inbuilt library for generating password like
WebSecurity.CreateUserAndAccount("username", "password");
it automatically generates password in table called "webpages_membership"
Note: I am using same database which is used by aps.net working website. so my website will be in asp.net and api will be now in php.
I found MembershipModel class in php which is used to compare two password but it can not generate password.
<?php
/*
* Author : Mr. Juned Ansari
* Date : 15/02/2017
* Purpose : It Handles Login Encryption And Decryption Related Activities
*/
class MembershipModel {
function bytearraysequal($source, $target) {
if ($source == null || $target == null || (strlen($source) != strlen($target)))
return false;
for ($ctr = 0; $ctr < strlen($target); $ctr++) {
if ($target[$ctr] != $source[$ctr])
return false;
}
return true;
}
//This Function is Used to verifypassword
function verifypassword($hashedPassword, $password) {
$PBKDF2IterCount = 1000; // default for Rfc2898DeriveBytes
$PBKDF2SubkeyLength = 32; // 256 bits
$SaltSize = 16; // 128 bits
if ($hashedPassword == null) {
return false;
//show_error("hashedPassword is null");
}
if ($password == null) {
return false;
//show_error("Password is null");
}
$hashedPasswordBytes = base64_decode($hashedPassword);
if (strlen($hashedPasswordBytes) != 48) {
return false;
}
$salt = substr($hashedPasswordBytes, 0, $SaltSize);
$storedSubkey = substr($hashedPasswordBytes, $SaltSize, $PBKDF2SubkeyLength);
$generatedSubkey = $this->encript('sha1', $password, $salt, $PBKDF2IterCount, $PBKDF2SubkeyLength, true);
return $this->bytearraysequal($storedSubkey, $generatedSubkey);
}
function encript($algorithm, $password, $salt, $count, $key_length, $raw_output = false) {
$algorithm = strtolower($algorithm);
if (!in_array($algorithm, hash_algos(), true))
return false;
//show_error('PBKDF2 ERROR: Invalid hash algorithm.');
if ($count <= 0 || $key_length <= 0)
return false;
//show_error('PBKDF2 ERROR: Invalid parameters.');
$hash_length = strlen(hash($algorithm, "", true));
$block_count = ceil($key_length / $hash_length);
$output = "";
for ($i = 1; $i <= $block_count; $i++) {
$last = $salt . pack("N", $i);
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
for ($j = 1; $j < $count; $j++) {
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}
return substr($output, 0, $key_length);
}
}
I have successfully created Login APi in PHP which is working fine using above class.
As all the comments are advising you, you’re probably doing it the hard way if you try to port this work over to PHP instead of letting PHP talk to the backend via some .NET component.
Nevertheless, if you’re set on porting it over, the code for WebSecurity.CreateUserAndAccount() is available on GitHub. As you can see, it leans on the currently-configured membership provider's implementation of that method.
For SimpleMembershipProvider, the implementation is very simple. Here’s the important bit:
CreateUserRow(db, userName, values);
return CreateAccount(userName, password, requireConfirmation);
CreateUserRow() isn't very interesting or surprising, but CreateAccount() is responsible for the part I think you care about.
There are two parts that you'd need to port to PHP; Crypto.HashPassword() and GenerateToken(). Since you're calling WebSecurity.CreateUserAndAccount() with only two parameters, you can ignore the GenerateToken() part (since requireConfirmation defaults to false).
Here's the source code for Crypto.HashPassword(). As per its comment, it performs:
PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations.
(See also: SDL crypto guidelines v5.1, Part III)
Format: { 0x00, salt, subkey }
…using the System.Security.Cryptography.Rfc2898DeriveBytes() method.
Which leads us to this directly related existing Stack Overflow answer, which I think gives you what you want.
Related
I am working on an ASP.NET MVC 5 web application inside VS 2012 and I am using IIS 8 to deploy the web application.
I have a security token which I am using to call a third party WebAPI. Currently inside my controller class, I define and use the token as follows:
string token = "D12356";
string url = currentURL + "resources?AUTHTOKEN=" + token;
Is there is a way to encrypt this value, so if anyone accesses the code inside VS or anyone reverse engineers the .dll files on IIS they won't see the actual token value, but will instead see the encrypted value?
Is there is a way to encrypt this value, so if anyone accesses the code inside VS or anyone reverse engineers the .dll files on IIS they won't see the actual token value, but will instead see the encrypted value?
Well, yes, you can embed an encrypted value in the code, but the problem is that whoever decompiles the library will also see how you decrypt it.
Since you're talking about ASP.NET, your web.config is just as vulnerable as your source code, so there's no added security there.
The solution is to either store the value somewhere secure outside of your web app (secured database?), or use some external value as part of your decryption process, like a certificate or other private key value.
The following class has the encryption and decryption process, through which one can encrypt or decrypt its data with the provision of some values i.e.
Key = string / byte[] to encrypt or decrypt the input
Input = the user required field on which he wants to apply cryptography
Please write this class as follows:
namespace SomeNameSpace
{
public enum CryptType { ENCRYPT, DECRYPT }
public enum CryptTechnique { AES, RC2, RIJ, DES, TDES }
public class Cryptography
{
public object Crypt(CryptType EncryptOrDecrypt, CryptTechnique CryptographicTechnique, object Input, string Key)
{
try
{
SymmetricAlgorithm SymAlgo; //This class is parent of all classes in CryptTechnique enums
switch (CryptographicTechnique)
{
case CryptTechnique.AES:
SymAlgo = new AesManaged();
break;
case CryptTechnique.RC2:
SymAlgo = new RC2CryptoServiceProvider();
break;
case CryptTechnique.RIJ:
SymAlgo = new RijndaelManaged();
break;
case CryptTechnique.DES:
SymAlgo = new DESCryptoServiceProvider();
break;
case CryptTechnique.TDES:
SymAlgo = new TripleDESCryptoServiceProvider();
break;
default:
return false;
}
SymAlgo.Key = UTF8Encoding.UTF8.GetBytes(Key);
SymAlgo.Padding = PaddingMode.PKCS7;
SymAlgo.Mode = CipherMode.ECB;
ICryptoTransform ICT = null;
byte[] resultArray;
if(EncryptOrDecrypt == CryptType.ENCRYPT)
{
ICT = SymAlgo.CreateEncryptor();
}
else if(EncryptOrDecrypt == CryptType.DECRYPT)
{
ICT = SymAlgo.CreateDecryptor();
}
if (Input is string)
{
byte[] inputArray = UTF8Encoding.UTF8.GetBytes(Input as string);
resultArray = ICT.TransformFinalBlock(inputArray, 0, inputArray.Length);
SymAlgo.Clear();
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
else if (Input is byte[])
{
resultArray = ICT.TransformFinalBlock(Input as byte[], 0, (Input as byte[]).Length);
SymAlgo.Clear();
return resultArray;
}
return false;
}catch(Exception ex)
{
return ex.Message;
}
}
}
}
and in some controller where you want to encrypt or decrypt data, write there as
public ActionResult SomeAction()
{
string Key = "1234567890abcdef"; //key must have 16 chars, other wise you may get error "key size in not valid".
Password = "Secret";
Cryptography Crypt = new Cryptography();
EncryptedPassword = (string)Crypt.Crypt(CryptType.ENCRYPT, CryptTechnique.RIJ, Password, Key);
}
Here you will get the encrypted password in EncryptedPassword variable
I can't seem to get the right data returned. Here is my PHP code:
<?php
$u = $_GET['u'];
$p = $_GET['p'];
require_once("models/config.php");
if (!securePage($_SERVER['PHP_SELF'])){die();}
//Prevent the user visiting the logged in page if he/she is already logged in
if(isUserLoggedIn()) { header("Location: account.php"); die(); }
//Forms posted
if(!empty($_POST))
{
$errors = array();
$username = sanitize(trim($_POST[$u]));
$password = trim($_POST[$p]);
//Perform some validation
//Feel free to edit / change as required
if($username == "")
{
$errors[] = lang("ACCOUNT_SPECIFY_USERNAME");
}
if($password == "")
{
$errors[] = lang("ACCOUNT_SPECIFY_PASSWORD");
}
if(count($errors) == 0)
{
//A security note here, never tell the user which credential was incorrect
if(!usernameExists($username))
{
$errors[] = lang("ACCOUNT_USER_OR_PASS_INVALID");
}
else
{
$userdetails = fetchUserDetails($username);
//See if the user's account is activated
if($userdetails["active"]==0)
{
$errors[] = lang("ACCOUNT_INACTIVE");
}
else
{
//Hash the password and use the salt from the database to compare the password.
$entered_pass = generateHash($password,$userdetails["password"]);
if($entered_pass != $userdetails["password"])
{
//Again, we know the password is at fault here, but lets not give away the combination incase of someone bruteforcing
$errors[] = lang("ACCOUNT_USER_OR_PASS_INVALID");
return 0;
}
else
{
//Passwords match! we're good to go'
return 1;
//Update last sign in
$loggedInUser->updateLastSignIn();
$_SESSION["userCakeUser"] = $loggedInUser;
}
}
}
}
}
?>
It always returns incorrect details (0). Here is the C# code:
public static string Login(string user, string pass)
{
WebClient c = new WebClient();
string a = c.DownloadString("http://www.zilentsoftware.com/static/user/account/zlogin.php?u=" + user + "&p=" + pass);
return a;
}
It wont return the correct value - even when all the info is correct. I have no idea how to fix this! I want to check the username and their password against the database. This is the same method as the website login but it's not working. I've looked on the UserCake documentation and there is nothing!
Are you sure that this line
$entered_pass = generateHash($password,$userdetails["password"]);
does what you want?
You generate a hash with the password the user entered and the saved password in your db.
After this you compare this generated hash with the password you used before to hash the entered password. Which will always be false (except you hit a collision)
if($entered_pass != $userdetails["password"])
I think you maybe meant
$entered_pass = generateHash($password,$userdetails["hash"]);
or something similar because your comments say you use the hash to generate the password hash.
I don't know how you generateHash method works so I can't say for sure if this is the reason your application does not work as intended. You may also look at the statements after return because I am not sure if they will be executed
I'm trying to encrypt some data in Mono C#, send it to a NodeJS server and decrypt it there. I'm trying to figure out what algorithms to use to match the two.
I send the encrypted string encoded with base64. So I do something like this in Javascript, where I know the key which was used to encrypt the data in my C# application:
var decipher = crypto.createDecipher('aes192',binkey, biniv);
var dec = decipher.update(crypted,'base64','utf8');
dec += decipher.final('utf8');
console.log("dec", dec);
In Mono I create my Cypher with:
using System.Security.Cryptography;
using (Aes aesAlg = Aes.Create("aes192"))
I need to pass the correct string to Aes.Create() in order to have it use the same algorithm, but I can't find what it should be. "aes192" is not correct it seems.
I don't need aes192 this was just a tryout. Suggest a different encryption flavor if it makes sense. Security is not much of an issue.
Here are links to .NET and Nodejs docs:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.aes.aspx
http://nodejs.org/api/crypto.html
This code works for my Node.js side, but please replace the static iv, otherwhise aes encryption would be useless.
var crypto = require('crypto');
function encrypt(data, key) {
key = key || new Buffer(Core.config.crypto.cryptokey, 'binary'),
cipher = crypto.createCipheriv('aes-256-cbc', key.toString('binary'), str_repeat('\0', 16));
cipher.update(data.toString(), 'utf8', 'base64');
return cipher.final('base64');
}
function decipher(data, key) {
key = key || new Buffer(Core.config.crypto.cryptokey, 'binary'),
decipher = crypto.createDecipheriv('aes-256-cbc', key.toString('binary'), str_repeat('\0', 16));
decipher.update(data, 'base64', 'utf8');
return decipher.final('utf8');
}
function str_repeat(input, multiplier) {
var y = '';
while (true) {
if (multiplier & 1) {
y += input;
}
multiplier >>= 1;
if (multiplier) {
input += input;
} else {
break;
}
}
return y;
}
I hope this helps You.
NOTE: You need to deliver an 265bit aka 32 character key for this algorithm to work.
POSSIBLE .NET SOLUTION: This may help you Example
You should simply write new AesManaged().
You don't need to call Create().
You then need to set Key and IV, then call CreateDecryptor() and put it in a CryptoStream.
It turned out to be a stupid mistake. I thought the create function in Node.js could take a variable argument count. Turns out you need to call the createDecipheriv() instead.
Just for the record, you can easily check the padding and mode by looking at those properties in the Aes object. The defaults are CBC and PKCS7. That padding is also used in nodejs crypto. So a for a 128 key size my code to decrypt a base64 encoded string would be:
var crypto = require('crypto');
var binkey = new Buffer(key, 'base64');
var biniv = new Buffer(iv, 'base64');
var decipher = crypto.createDecipheriv('aes-128-cbc', binkey, biniv);
var decrypted = decipher.update(crypted,'base64','utf8');
decrypted += decipher.final('utf8');
console.log("decrypted", decrypted);
How can I programmatically get when X509Certificate is revoked? I can get information if certificate is revoked, but i need to get when is revoked, i think that CRL list have that info, but can someone tell me how to read that.
Revocation status is checked by (a) obtaining CRL lists and checking if the certificate is listed there, and (b) sending an OCSP request to the server to check the same.
.NET doesn't let you do this. CryptoAPI might have some means for these operations, but the easiest is to use third-party library for .NET. BouncyCastle claims to have some support for OCSP and CRLs, and our SecureBlackbox provides complete support (both client and server components are available) for OCSP and CRL, and also we provide a component which performs complete certificate validation (with all CRL and OCSP checks and HTTP and LDAP communication when needed) with one method call.
The CRL is stored as an OID in the extensions property of the X509Certificate object. The OID FriendlyName and Value are 'CRL Distribution Points' and '2.5.29.31'. Searching the certificate's extensions for an OID with value 2.5.29.31, you can then parse the raw data and get the distribution point(s).
I found the following code sample here. I tested it on both publicly sign certs and internal Microsoft CA certs; it returns the URL or LDAP connection string.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace System.Security.Cryptography.X509Certificates
{
public static class X509Certificate2Extensions
{
/// <summary>
/// Returns an array of CRL distribution points for X509Certificate2 object.
/// </summary>
/// <param name="certificate">X509Certificate2 object.</param>
/// <returns>Array of CRL distribution points.</returns>
public static string[] GetCrlDistributionPoints(this X509Certificate2 certificate)
{
X509Extension ext = certificate.Extensions.Cast<X509Extension>().FirstOrDefault(
e => e.Oid.Value == "2.5.29.31");
if (ext == null || ext.RawData == null || ext.RawData.Length < 11)
return EmptyStrings;
int prev = -2;
List<string> items = new List<string>();
while (prev != -1 && ext.RawData.Length > prev + 1)
{
int next = IndexOf(ext.RawData, 0x86, prev == -2 ? 8 : prev + 1);
if (next == -1)
{
if (prev >= 0)
{
string item = Encoding.UTF8.GetString(ext.RawData, prev + 2, ext.RawData.Length - (prev + 2));
items.Add(item);
}
break;
}
if (prev >= 0 && next > prev)
{
string item = Encoding.UTF8.GetString(ext.RawData, prev + 2, next - (prev + 2));
items.Add(item);
}
prev = next;
}
return items.ToArray();
}
static int IndexOf(byte[] instance, byte item, int start)
{
for (int i = start, l = instance.Length; i < l; i++)
if (instance[i] == item)
return i;
return -1;
}
static string[] EmptyStrings = new string[0];
}
}
use this API from x509.h file use openssl 1.0 / or above version
X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x);
X in the certificate u want to check ;
Ret is the Address of the revocation structure where reason for the revocation and all stored
crl is the CRL .
For future readers.
As already was said, .NET currently do not expose public classes nor for X.509 certificate revocation lists, nor for OCSP messaging. Of course, you can write your own code or to use 3rd party libraries.
You can try my own CryptoAPI managed extensions from PowerShell PKI module project (PKI.Core.dll library). There is a support for X509 CRL managed class (built on top of CryptoAPI native functions): X509CRL2 class. RevokedCertificates property stores an array of revoked certificates. In addition, library includes OCSP messaging classes (completely managed) stored in PKI.OCSP namespace. If your certificate contains OCSP links in the AIA extension, then you can easyly construct OCSP request from X509Certificate2 object by instantiating OCSPRequest object and invoking OCSPRequest.SendRequest method. Return object is an instance of OCSPResponse class.
Basically, the code woul look as this:
using System;
using System.Security.Cryptography.X509Certificates;
using PKI.OCSP;
public class Class1 {
public static DateTime? GetrevocationDate(X509Certificate2 cert) {
OCSPRequest request = new OCSPRequest(cert);
OCSPResponse response = request.SendRequest();
if (response.Responses[0].CertStatus == CertificateStatus.Revoked) {
return response.Responses[0].RevocationInfo.RevocationDate;
}
return null;
}
}
NULL would mean that the certificate is not revoked.
with X509 CRL the code would look as this:
using System;
using System.Security.Cryptography.X509Certificates;
public class Class1 {
// crlRawData could a type of System.String and pass the path to a CRL file there.
public static DateTime? GetrevocationDate(X509Certificate2 cert, Byte[] crlRawData) {
X509CRL2 crl = new X509CRL2(crlRawData);
X509CRLEntry entry = crl.RevokedCertificates[cert.SerialNumber];
if (entry != null) {
return entry.RevocationDate;
}
return null;
}
}
I don't have the reputation to upvote #Hive's answer above but it was exactly what I needed, except for the language. I've posted my PowerShell port below:
$cert = (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Subject -match "SUBJECT NAME*"})
function IndexOfByte([byte[]]$instance, [byte]$item, [int]$start)
{
$len = $instance.Length
for ($i = $start; $i -lt $len; $i++) {
if ($instance[$i] -eq $item) { return $i }
}
return -1;
}
$crls = $cert.Extensions | ? { $_.Oid.FriendlyName -eq "CRL Distribution Points" }
$prev = -2;
[System.Collections.ArrayList]$items = #();
while ($prev -ne -1 -and $crls.RawData.Length -gt $prev + 1)
{
if($prev -eq -2) { $y = 8 } else {$y = $prev + 1}
$next = IndexOfByte -instance $crls.RawData -item 0x86 -start $y
if ($next -eq -1) {
if ($prev -ge 0) {
$item = [system.Text.Encoding]::UTF8.GetString($crls.RawData, $prev + 2, $crls.RawData.Length - ($prev + 2));
$items.Add($item);
}
break;
}
if ($prev -ge 0 -and $next -gt $prev) {
$item = [system.Text.Encoding]::UTF8.GetString($crls.RawData, $prev + 2, $next - ($prev + 2));
$items.Add($item);
}
$prev = $next;
}
Write-Host "Certificate CRLs: `n$($items | out-string)"
This could help you:
http://blogs.msdn.com/b/alejacma/archive/2010/05/10/how-to-get-info-from-client-certificates-issued-by-a-ca-c.aspx
Regards.
The first step is to extract the CRL distribution points from the certificate, and then match your certificate's serial number against the content of the CRL from the distribution point.
Here's an alternative way to extract the CRL distribution points with fewer magic numbers and bit twiddling. (tested in .NET Core 2.1)
var path = "<path to signed file>";
// get certificate
var cert = new X509Certificate2(path);
// extract the CRL distribution points information
var crlInfo = cert.Extensions["2.5.29.31"];
var crlDistribitionPoints = new AsnEncodedData(crlInfo.Oid, crlInfo.RawData).Format(false);
Console.Writeline(crlDistribitionPoints);
When you say revoked, do you mean invalid? If its revoked I wouldn't expect it to arrive at the request in your code as the web server will have got in the way first.
If you use the x509certificate2, which is derived from x509certificate, then you have a lot more properties which you can check; there are a number of examples on the link below.
http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.aspx
I'm trying to write a c# version of some php sample code for Facebook authentication which I found here: http://developers.facebook.com/docs/guides/web/ The php in the example is:
define('YOUR_APP_ID', 'your app id ');
define('YOUR_APP_SECRET', 'your app secret');
function get_facebook_cookie($app_id, $app_secret) {
$args = array();
parse_str(trim($_COOKIE['fbs_' . $app_id], '\\"'), $args);
ksort($args);
$payload = '';
foreach ($args as $key => $value) {
if ($key != 'sig') {
$payload .= $key . '=' . $value;
}
}
if (md5($payload . $app_secret) != $args['sig']) {
return null;
}
return $args;
}
And my C# version is:
private bool CheckFacebookAuthentication()
{
var appSecret = "??????????";
var appId = "?????";
var cookie = Request.Cookies["fbs_" + appId];
var payload = "";
foreach (var key in cookie.Values.AllKeys.OrderBy(x => x))
{
if (key != "sig")
{
payload += key.Trim("\"".ToCharArray()) + "=" + cookie.Values[key].Trim("\"".ToCharArray());
}
}
if (cookie.Values["sig"] == FormsAuthentication.HashPasswordForStoringInConfigFile(payload + appSecret, "md5"))
{
return true;
}
return false;
}
I appreciate that my c# version is not doing quite the same thing as the php i.e. it is just checking that the signature is valid and returning a boolean indicating this; whereas the php is returning an array if it is valid.
But the issue I have is that my c# version is not validating cookies that I would expect to be valid. My experience of php is limited, so I expect I have misinterpreted something from the php example when writing my c# version.
Is there anything obviously wrong with my c# interpretation of this php?
Yes, that is the correct translation, but you could replace "\"".ToCharArray() with just '\"'
Also, there is a pretty good SDK written in C# for Facebook here: http://facebooksdk.codeplex.com/
That is if you want to look at some more example code.
I've worked a lot with Facebook's Graph APIs and C#, so if there is anything specific you need help with, feel free to ask :)
I would say it is not the corresponding translation. As far as I can see it boils down to this line:
parse_str(trim($_COOKIE['fbs_' . $app_id], '\\"'), $args);
Here in PHP the cookie string is trimmed by removing any '\' or '"' character (check the php manual for trim(...)) and then parsed whereas in C# you are currently trimming each value and key individually, try removing this.