PBKDF2 iterations - asp.net-mvc

I am using simplemembershipprovider in ASP.NET for authentication.
Microsoft's built in crypto method (below) uses 1000 iterations when hashing passwords. Everyone says this is not enough, so my question is: how could I change this? Surely there is a simple way for me to change one number from 1000 to 100000? I don't want to produce my own security code because people say that for an inexperienced developer security code should be kept away. Do I just accept that 1000 is what it is?
/* =======================
* HASHED PASSWORD FORMATS
* =======================
*
* Version 0:
* 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 }
*/
public static string HashPassword(string password)
{
if (password == null)
{
throw new ArgumentNullException("password");
}
// Produce a version 0 (see comment above) password hash.
byte[] salt;
byte[] subkey;
using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount))
{
salt = deriveBytes.Salt;
subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
byte[] outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];
Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength);
return Convert.ToBase64String(outputBytes);
}

Related

How to get USB Token (Feitian Auto ePass 2003 FIPS USB Token) serial number in UEFI Application?

Developing UEFI Based application for enabling pre-boot authentication using
Feitian Auto ePass 2003 FIPS USB Token. I'm still in the initial stage of the development process.
Now I'm able to fetch Manufacturer, Product Code of the token by using UsbIo->UsbGetDeviceDescriptor protocol. But when I try to find serial number it's throwing an error.
Is there any other way to find the serial number of the USB Token? Please help me on this..
This is my sample code for finding serial number
EFI_USB_DEVICE_DESCRIPTOR DevDesc;
EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
EFI_USB_CONFIG_DESCRIPTOR ConfigDescriptor;
EFI_USB_IO_PROTOCOL *UsbIo;
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer = NULL;
BOOLEAN LangFound;
UINTN HandleCount;
UINT8 EndpointNumber;
CHAR16* ManufacturerString = NULL;
CHAR16* ProductString = NULL;
CHAR16* SerialNumber = NULL;
UINT16* LangIDTable;
UINT16 TableSize;
INTN Index;
int index;
unsigned char* device_descriptor, * ccid_descriptor;
EFI_USB_DEVICE_REQUEST DevReq;
UINT32 Status_uint;
Status = gBS->LocateHandleBuffer( ByProtocol,
&gEfiUsbIoProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer );
if (EFI_ERROR(Status)) {
Print(L"ERROR: LocateHandleBuffer.\n");
goto ErrorExit;
}
UINT8 usbIndex;
for (usbIndex = 0; usbIndex < HandleCount; usbIndex++) {
Status = gBS->HandleProtocol( HandleBuffer[usbIndex],
&gEfiUsbIoProtocolGuid,
(VOID**)&UsbIo );
if (EFI_ERROR(Status)) {
Print(L"ERROR: Open UsbIo.\n");
goto ErrorExit;
}
Status = UsbIo->UsbGetDeviceDescriptor( UsbIo, &DevDesc );
if (EFI_ERROR(Status)) {
Print(L"ERROR: UsbGetDeviceDescriptor.\n");
goto ErrorExit;
}
Status = UsbIo->UsbGetConfigDescriptor( UsbIo, &ConfigDescriptor );
if (EFI_ERROR (Status))
{
Print(L"UsbGetConfigDescriptor %d", Status);
goto ErrorExit;
}
Status = UsbIo->UsbGetInterfaceDescriptor( UsbIo, &InterfaceDescriptor );
if (EFI_ERROR (Status)) {
Print(L"ERROR: UsbGetInterfaceDescriptor.\n");
goto ErrorExit;
}
if (InterfaceDescriptor.InterfaceClass != CLASS_CCID) {
continue;
}
Print(L":::::::::::::::::::::: CCID ::::::::::::::::::::::\n");
//
// Get all supported languages.
//
TableSize = 0;
LangIDTable = NULL;
Status = UsbIo->UsbGetSupportedLanguages(UsbIo, &LangIDTable, &TableSize);
if (EFI_ERROR(Status)) {
Print(L"ERROR: UsbGetSupportedLanguages.\n");
return Status;
}
/* Get Manufacturer string */
for (Index = 0; Index < TableSize / sizeof(LangIDTable[0]); Index++) {
ManufacturerString = NULL;
Status = UsbIo->UsbGetStringDescriptor(UsbIo,
LangIDTable[Index],
DevDesc.StrManufacturer,
&ManufacturerString);
if (EFI_ERROR(Status) || (ManufacturerString == NULL)) {
continue;
}
Print(L"StrManufacturer ::%s\n", ManufacturerString);
FreePool(ManufacturerString);
break;
}
/* Get Product string */
for (Index = 0; Index < TableSize / sizeof(LangIDTable[0]); Index++) {
ProductString = NULL;
Status = UsbIo->UsbGetStringDescriptor(UsbIo,
LangIDTable[Index],
DevDesc.StrProduct,
&ProductString);
if (EFI_ERROR(Status) || (ProductString == NULL)) {
continue;
}
Print(L"StrProduct ::%s\n", ProductString);
FreePool(ProductString);
break;
}
/* Get Serial string */
for (Index = 0; Index < TableSize / sizeof(LangIDTable[0]); Index++) {
SerialNumber = NULL;
Status = UsbIo->UsbGetStringDescriptor(UsbIo,
LangIDTable[Index],
DevDesc.StrSerialNumber,
&SerialNumber);
if (EFI_ERROR(Status) || (SerialNumber == NULL)) {
Print(L"Error in finding SerialNumber \n");
continue;
}
Print(L"SerialNumber :: %s\n", SerialNumber);
FreePool(SerialNumber);
break;
}
Print(L"usbIndex ::%d\n", usbIndex);
Print(L"IdVendor ::%d\n", DevDesc.IdVendor);
Print(L"IdProduct ::%d\n", DevDesc.IdProduct);
}
Print(L"\n");
FreePool(HandleBuffer);
return Status;
From what I have read, the Feitian Technologies ePass2003 uses an Infineon M7893 or SLE 78CUFX5000PH (M7893-B) security chip.
As you have found out, the serial number for the ePass2003 is not stored in the USB device descriptor but in the security chip.
To obtain chip global data such as OEM information, algorithm support, FIPS mode indicator, RAM size and serial number, the GetData primitive is used. See the M7893 programming guide. if you can obtain access to it.
The driver for ePass2003 in OpenSC is called “epass2003”. The source code is currently available at https://github.com/OpenSC/OpenSC/blob/master/src/libopensc/card-epass2003.c. It has dependencies on OpenSSL and ASN.1 and some non-EDK2 headers, but these are easily worked around.
If all you are looking for is the serial number, it should be fairly easy to write a UEFI application (or driver) to get that information either by studying how the OpenSC ePass2003 driver does it (hint - look at epass2003_get_serialnr or studying the ePass2003 SDK which is available for free from Feitain and elsewhere.
The UEFI 2.5 specification released in April 2015 detailed 2 protocols relating to smart cards, i.e. Smart Card Reader and Smart Card Edge.
typedef struct _EFI_SMART_CARD_READER_PROTOCOL {
EFI_SMART_CARD_READER_CONNECT SCardConnect;
EFI_SMART_CARD_READER_DISCONNECT SCardDisconnect;
EFI_SMART_CARD_READER_STATUS SCardStatus;
EFI_SMART_CARD_READER_TRANSMIT SCardTransmit;
EFI_SMART_CARD_READER_CONTROL SCardControl;
EFI_SMART_CARD_READER_GET_ATTRIB SCardGetAttrib;
} EFI_SMART_CARD_READER_PROTOCOL;
typedef struct _EFI_SMART_CARD_EDGE_PROTOCOL {
EFI_SMART_CARD_EDGE_GET_CONTEXT GetContext;
EFI_SMART_CARD_EDGE_CONNECT Connect;
EFI_SMART_CARD_EDGE_DISCONNECT Disconnect;
EFI_SMART_CARD_EDGE_GET_CSN GetCsn;
EFI_SMART_CARD_EDGE_GET_READER_NAME GetReaderName;
EFI_SMART_CARD_EDGE_VERIFY_PIN VerifyPin;
EFI_SMART_CARD_EDGE_GET_PIN_REMAINING GetPinRemaining;
EFI_SMART_CARD_EDGE_GET_DATA GetData;
EFI_SMART_CARD_EDGE_GET_CREDENTIAL GetCredential;
EFI_SMART_CARD_EDGE_SIGN_DATA SignData;
EFI_SMART_CARD_EDGE_DECRYPT_DATA DecryptData;
EFI_SMART_CARD_EDGE_BUILD_DH_AGREEMENT BuildDHAgreement;
} EFI_SMART_CARD_EDGE_PROTOCOL;
EDK2 does not contain a sample implementation at present. However, you may be interested in the GPL2-licensed sample implementation by Ludovic Rousseau which is available at https://github.com/LudovicRousseau/edk2/tree/SmartCard. The implementation code, which is circa 5 years old and which I have not tested, is at MdeModulePkg/Library/SmartCardReader. Read his blog (https://ludovicrousseau.blogspot.com/) also as he provides useful sample applications also.

How do I determine an expired access token?

I am interfacing with the Microsoft Health Cloud API and have successfully requested an access token and refresh token. Communication with the RESTful API works as intended, although I am having a hard time figuring out, how to reliably determine an expired access token.
I have the following code in place:
fire_and_forget read_profile()
{
HttpClient httpClient{};
httpClient.DefaultRequestHeaders().Authorization({ L"bearer", access_token_ });
try
{
auto const response{ co_await httpClient.GetStringAsync({ L"https://api.microsofthealth.net/v1/me/Profile" }) };
// Raise event passing the response along.
// Code left out for brevity.
co_return;
}
catch (hresult_error const& e)
{
if (e.code() != 0x80190191) // Magic value for "unauthorized access (401)"
{
throw;
}
// This is an "unauthorized access (401)" error. Continue with requesting a new
// access token from the refresh token.
// Code left out for brevity.
}
Although it appears to work, it feels wrong for so many reasons. It's not just the magic value, but also the fact, that this particular error code may be used for other error modes.
Is there a more robust way of determining, whether an access token has expired?
Note: I understand, that I could use the expiration interval, and check against the system time. I'd rather not go down that route, as it isn't entirely reliable either, and introduces additional complexity for roaming that information across devices.
I understand, that I could use the expiration interval, and check against the system time.
Microsoft Health Cloud API has provided expires_in field to verify the token is valid. In general, we could check against the system time, and if the system time was artificially modified, it isn't entirely reliable. So we could use NTP server time, rather than use system time.
public async static Task<DateTime> GetNetworkTime()
{
//default Windows time server
const string ntpServer = "time.windows.com";
// NTP message size - 16 bytes of the digest (RFC 2030)
var ntpData = new byte[48];
//Setting the Leap Indicator, Version Number and Mode values
ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
var addresses = await Dns.GetHostAddressesAsync(ntpServer);
//The UDP port number assigned to NTP is 123
var ipEndPoint = new IPEndPoint(addresses[0], 123);
//NTP uses UDP
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
{
socket.Connect(ipEndPoint);
//Stops code hang if NTP is blocked
socket.ReceiveTimeout = 3000;
socket.Send(ntpData);
socket.Receive(ntpData);
socket.Dispose();
}
//Offset to get to the "Transmit Timestamp" field (time at which the reply
//departed the server for the client, in 64-bit timestamp format."
const byte serverReplyTime = 40;
//Get the seconds part
ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
//Get the seconds fraction
ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
//Convert From big-endian to little-endian
intPart = SwapEndianness(intPart);
fractPart = SwapEndianness(fractPart);
var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
//**UTC** time
var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);
return networkDateTime.ToLocalTime();
}
// stackoverflow.com/a/3294698/162671
static uint SwapEndianness(ulong x)
{
return (uint)(((x & 0x000000ff) << 24) +
((x & 0x0000ff00) << 8) +
((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24));
}

Error verifying message using Crypto++ on iOS

Problem
I am trying to verify a given message with its signature and public key. It works fine using the iOS provided Security Framework, but I cannot manage to make it work using the Crypto++ library (must use).
I followed the same steps using the CryptoPP Library and verified everything 10 times, rewrote some parts differently, but it still throws the same exception:
"PK_Signer: key too short for this signature scheme"
context
Data worked with
I receive a JWT (Json Web Token) with a header, payload and signature.
I retrieve the service's base64 encoded X509 certificate (which includes the public key).
Steps followed for verification
Certificate
Base64 decode the certificate
Extract the public key from certificate
Signature (third segment of a JWB)
Pad the signature to a multiple of 4 with some "="
URLBase64 decode it
Message to verify
Message = (JSW Header) + "." + (JWT Payload). This is already done in the code, message is argument named "headerAndPayload.
Verify SHA256 bytes with PKCS1, RSA
SHA256 digest of the Message
Verification using:
Public Key
SHA256 Digest of the message
Signature
iOS Working Code
(Only parts that matter, as verification works fine on iOS)
Certificate
NSData *certificateData = [[NSData alloc] initWithBase64EncodedString:certificateString options:0];
SecKeyRef getPublicKeyFromCertificate(certificateData) found online, works fine.
Verify SHA256 bytes with PKCS1, RSA
BOOL PKCSVerifyBytesSHA256withRSA(NSData* message, NSData* signature, SecKeyRef publicKey)
{
size_t signedHashBytesSize = SecKeyGetBlockSize(publicKey);
const void* signedHashBytes = [signature bytes];
size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH;
void* hashBytes = malloc(hashBytesSize);
if (!CC_SHA256([message bytes], (CC_LONG)[message length], hashBytes)) {
return NULL;
}
OSStatus status = SecKeyRawVerify(publicKey,
kSecPaddingPKCS1SHA256,
hashBytes,
hashBytesSize,
signedHashBytes,
signedHashBytesSize);
return status == errSecSuccess;
}
Code using CryptoPP Library (working with same set of data)
I copy/paste the whole code with numbers corresponding to the description and some additional comments, like size of structures returned.
+(bool)verifyBase64EncodedCertificate:(NSString *)certificateString
base64URLEncodedJWTSignature:(NSString *)urlEncodedSignature
message:(NSString *)headerAndPayload
{
// 1. Certificate
// 1.1 Decode the certificate
std::string base64EncodedCertificate = certificateString.UTF8String;
std::string decodedCertificate;
CryptoPP::StringSource ss(base64EncodedCertificate,
true,
new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decodedCertificate))
);
// 1.2 Extract Public Key from certificate
CryptoPP::ByteQueue certificateByteQueue, publicKeyByteQueue;
certificateByteQueue.Put((byte *)&decodedCertificate[0], decodedCertificate.size());
certificateByteQueue.MessageEnd();
try
{
GetPublicKeyFromCert(certificateByteQueue, publicKeyByteQueue);
// This method comes from CryptoPP docs so I assume it works... certificate gets checked again later on.
}
catch(std::exception &)
{
std::cerr << "Failed to extract the public key from the CA certificate." << std::endl;
return nil;
}
//publicKeyByteQueue.CurrentSize() = 294
// 2. Decode Signature
std::string base64URLEncodedSignature = urlEncodedSignature.UTF8String;
unsigned long paddingForURLEncodedSignature = 4 - (base64URLEncodedSignature.length() % 4);
base64URLEncodedSignature.insert(base64URLEncodedSignature.begin(), paddingForURLEncodedSignature, '=');
std::string decodedSignature;
CryptoPP::StringSource ss1(base64URLEncodedSignature,
true,
new CryptoPP::Base64URLDecoder(new CryptoPP::StringSink(decodedSignature))
);
const byte *decodedSignaturePointer = (byte *)&decodedSignature[0];
size_t decodedSignatureSize = decodedSignature.size();
// Certificate Signature as Byte Block
CryptoPP::SecByteBlock certSignature;
certSignature.Assign(decodedSignaturePointer, decodedSignatureSize);
// decodedSignatureSize = 256
// certSignature.size() = 256
// 3. Message to verify (available already concatenated)
std::string message = headerAndPayload.UTF8String;
const byte *messagePointer = (const byte *)message.c_str();
const size_t messageLength = message.length();
// MessageLength = 693
// 4.1 hash message using SHA256
byte digest [CryptoPP::SHA256::DIGESTSIZE];
CryptoPP::SHA256().CalculateDigest(digest, messagePointer, messageLength);
// 4.2 Create Verifier assigned public key and test
CryptoPP::AutoSeededRandomPool prng;
CryptoPP::RSASS<CryptoPP::PKCS1v15, CryptoPP::SHA256>::Verifier verifier;
verifier.AccessKey().Load(publicKeyByteQueue);
if (!verifier.AccessKey().Validate(prng, 3))
{
throw CryptoPP::Exception(CryptoPP::Exception::OTHER_ERROR, "Failed to validate public key");
}
// verifier.SignatureLength() = 256 = certSignature.size()
if(certSignature.size() != verifier.SignatureLength())
{
std::cerr << "The signature size is does not match the algorithm used for signing." << std::endl;
return 0;
}
// 4. Actual Verification (1st way of doing it)
CryptoPP::SignatureVerificationFilter vf(verifier);
try
{
vf.Put(digest, CryptoPP::SHA256::DIGESTSIZE);
vf.Put(certSignature, certSignature.size());
vf.MessageEnd(); // Throws exception here PK_Signer: key too short for this signature scheme
}
catch(std::exception &e)
{
std::cerr << "Caught an exception while verifying the signature:" << std::endl;
std::cerr << "\t" << e.what() << std::endl;
return 0;
}
if(vf.GetLastResult())
{
std::cout << "The signature verified." << std::endl;
}
else
{
std::cout << "Signature verification failed." << std::endl;
}
return 1;
// 4. Actual Verification (2d way of doing it)
bool verified = verifier.VerifyMessage(digest, CryptoPP::SHA256::DIGESTSIZE,
decodedSignaturePointer, decodedSignatureSize);
// Also throw same exception PK_Signer: key too short for this signature scheme
return verified;
The only difference I can see between the pure iOS code and the CryptoPP code is during the verification process, the iOS method takes an additional argument kSecPaddingPKCS1SHA256
SecKeyRawVerify(publicKey,
kSecPaddingPKCS1SHA256,
...)
But otherwise I feel like I have replicated exactly the same concepts using the CryptoPP library.
Any help is very appreciated, thanks.
vf.Put(digest, CryptoPP::SHA256::DIGESTSIZE);
The signature is not the hash size. The signature is the size of the modulus (or more correctly, [0,n-1]). After protocol framing, the signature may be larger than the modulus size. Also see What is the length of an RSA signature? on the Cryptography Stack Exchange.
As for creating an equivalent iOS example, using the "Raw Sign" or "Raw Encrypt", see Raw RSA on the Crypto++ wiki. Its usually a bad idea for you to do the low level things like a modular exponentiation. You should try to stay in the protocols and cryptosystems, like RSASSA_PKCS1v15_SHA_Signer and RSASSA_PKCS1v15_SHA_Verifier.
Also checkout the RSASS class, which is RSA Signature Scheme. I'm guessing you will probably want a RSASS<PKCS1v15, SHA256>::Signer and RSASS<PKCS1v15, SHA256>::Verifier:
$ grep -IR Signer * | grep typedef
luc.h:typedef LUCSS<PKCS1v15, SHA>::Signer LUCSSA_PKCS1v15_SHA_Signer;
pubkey.h: typedef PK_FinalTemplate<TF_SignerImpl<SchemeOptions> > Signer;
pubkey.h: typedef PK_FinalTemplate<DL_SignerImpl<SchemeOptions> > Signer;
rsa.h:typedef RSASS<PKCS1v15, SHA>::Signer RSASSA_PKCS1v15_SHA_Signer;
rsa.h:typedef RSASS<PKCS1v15, Weak1::MD2>::Signer RSASSA_PKCS1v15_MD2_Signer;
rsa.h:typedef RSASS<PKCS1v15, Weak1::MD5>::Signer RSASSA_PKCS1v15_MD5_Signer;

Print the "showname" field attribute in tshark

Context
I've got a pcap file containing a bunch of beacon frames (in other words, I put my Wi-Fi adapter in monitor mode, started capturing while filtering on "wlan.fc.type_subtype == 0x08", and saved that).
Now, I want to, somehow, display specific fields of these packets. Among others:
SSID (wlan_mgt.ssid)
MAC (wlan.ta)
Current channel (wlan_mgt.ds.current_channel)
Group Cipher (wlan_mgt.rsn.gcs.type)
PairWise Ciphers (wlan_mgt.rsn.pcs.type)
Authentication Suite (wlan_mgt.rsn.akms.type)
I don't really care about the representation: plain text, xml, json, csv, X. I'm fine with it. I just don't want more data than I really need and the output needs to be meaningful to the human (wireshark newb) eye.
Eventually, I also want to filter the pcap to get a unique set and count the occurrences (some "|sort|uniq -c" will do), but let's not go there for now.
My solution so far
The first step could be, for example:
$ tshark -r capture.pcap -c 1 -T fields -e wlan_mgt.ssid -e wlan.ta -e wlan_mgt.ds.current_channel -e wlan_mgt.rsn.gcs.type -e wlan_mgt.rsn.pcs.type -e wlan_mgt.rsn.akms.type
MySSID XX:XX:XX:XX:XX:XX 2 4 4 2
After (manually) matching the numbers to their textual meaning, you get this:
SSID = MySSID
MAC (wlan.ta) = XX:XX:XX:XX:XX:XX
Current channel = 2
Group Cipher = Group Cipher Suite type: AES (CCM) (4)
PairWise Ciphers = Pairwise Cipher Suite type: AES (CCM) (4)
Authentication Suite = Auth Key Management (AKM) type: PSK (2)
This is what I'm looking for. But, as stated, I have to do it manually, which is not an option.
Question
Above you can see my current approach to the said goal. By doing
tshark -r capture.pcap -c 1 -T pdml
I get, for example (cutout):
<field name="wlan_mgt.rsn.pcs.list" showname="Pairwise Cipher Suite List 00-0f-ac (Ieee8021) AES (CCM)" size="4" pos="112" show="" value="">
<field name="wlan_mgt.rsn.pcs" showname="Pairwise Cipher Suite: 00-0f-ac (Ieee8021) AES (CCM)" size="4" pos="112" show="1027076" value="000fac04">
<field name="wlan_mgt.rsn.pcs.oui" showname="Pairwise Cipher Suite OUI: 00-0f-ac (Ieee8021)" size="3" pos="112" show="4012" value="000fac"/>
<field name="wlan_mgt.rsn.pcs.type" showname="Pairwise Cipher Suite type: AES (CCM) (4)" size="1" pos="115" show="4" value="04"/>
</field>
</field>
..., which tells me that tshark does have the information I need (in the form of the "showname" attribute).
Apparently, when working with "-T fields -e X", tshark outputs the value that's in the "show" attribute". I feel like I want what's behind the "showname" attribute. Unfortunately, after annoying google for a while I still don't know how or if this is even possible.
I'm also open to radically different ideas, but the main takeaway is that I can't part from the pcap file (which rules out iwlist, kismet, etc). I also preferably don't start writing search and replace rules to replace the meaningless numbers with their textual representation. I hope to solve it in cleaner way.
I kept messing with tshark for a while, until I decided that it couldn't be done. A little bit of programming using the amazing C++ library libtins got me where I needed to be.
The source is down below. Enjoy :)
#include <tins/tins.h>
#include <algorithm>
#include <iostream>
#include <map>
#include <string>
using namespace Tins;
using namespace std;
/*
* Container class for the data that is retrieved from the beacon.
*/
class Unit {
public:
/*
* Constructor. Parses the Dot11Beacon object and takes all the necessary
* data from it.
*/
Unit(Dot11Beacon& beacon);
Unit() = default;
unsigned getCount();
void incrementCount();
/*
* Prints this object onto the command line, in CSV format
*/
void print();
private:
string ssid;
string bssid;
unsigned channel;
unsigned count;
string gcs; // Group Cipher Suite
string pcs; // Pairwise Cipher Suite
string akm; // Authentication suite
/*
* Returns a string representation of a RSNInformation::CypherSuites enum value
*/
string type_to_string(const RSNInformation::CypherSuites& type);
/*
* Returns a string representation of a RSNInformation::AKMSuites enum value
*/
string type_to_string(const RSNInformation::AKMSuites& type);
};
Unit::Unit(Dot11Beacon& beacon) :
count {1} /* When this unit is created, it has been seen exactly once */ {
ssid = beacon.ssid();
bssid = beacon.addr3().to_string();
channel = unsigned(beacon.ds_parameter_set());
RSNInformation rsn;
for(const auto &opt : beacon.options()) {
if (opt.option() == Dot11::RSN) {
rsn = beacon.rsn_information();
// Put all authentication suite types in a string
const RSNInformation::akm_type& akmTypeList = rsn.akm_cyphers();
for (const auto& akmIt : akmTypeList) {
if (akm.size() == 0)
akm += type_to_string(akmIt);
else
akm += ";" + type_to_string(akmIt);
}
// Put all group cipher types in a string
const RSNInformation::CypherSuites& gcsType = rsn.group_suite();
gcs = type_to_string(gcsType);
// Put all pairwise ciphers in a string
const RSNInformation::cyphers_type& pcsTypeList = rsn.pairwise_cyphers();
for (const auto& pcsIt : pcsTypeList) {
if (pcs.size() == 0)
pcs += type_to_string(pcsIt);
else
pcs += ";" + type_to_string(pcsIt);
}
}
}
}
unsigned Unit::getCount() {
return count;
}
void Unit::incrementCount() {
count += 1;
}
void Unit::print() {
string ssid_to_print;
if (ssid.length() == 0) {
ssid_to_print = "<ZERO_LENGTH>";
} else if (!isprint(ssid[0])) {
ssid_to_print = to_string(static_cast<int>(ssid[0]));
} else {
ssid_to_print = ssid;
}
if (find(ssid_to_print.begin(), ssid_to_print.end(), ',') != ssid_to_print.end()) {
ssid_to_print = "\"" + ssid_to_print + "\"";
}
cout << ssid_to_print << ","
<< bssid << ","
<< to_string(channel) << ","
<< to_string(count) << ","
<< gcs << ","
<< pcs << ","
<< akm << endl;
}
string Unit::type_to_string(const RSNInformation::CypherSuites& type) {
switch (type) {
case RSNInformation::CypherSuites::CCMP:
return "CCMP";
break;
case RSNInformation::CypherSuites::TKIP:
return "TKIP";
break;
case RSNInformation::CypherSuites::WEP_104:
return "WEP_104";
break;
case RSNInformation::CypherSuites::WEP_40:
return "WEP_40";
break;
}
}
string Unit::type_to_string(const RSNInformation::AKMSuites& type) {
switch (type) {
case RSNInformation::AKMSuites::PMKSA:
return "PMKSA";
break;
case RSNInformation::AKMSuites::PSK:
return "PSK";
break;
}
}
/*
* Class that reads the pcap, keeps track of the units and writes out one
* beacon frame in pcap format for each unique AP it finds. This file is called
* "unique_beacons.pcap"
*/
class PCAPParser {
public:
/*
* Constructor. It takes the exact parameters that it will pas on to its
* FileSniffer object (a FileSniffer is actually just a file reader).
*/
PCAPParser(const string& pcapFilename, const string& filter);
/*
* Start reading the file.
*/
bool run();
/*
* Print CSV header and ask all of our collected Unit objects to print themselves
*/
void print();
private:
FileSniffer sniffer;
PacketWriter writer;
map<string, Unit> apMap; // stands for Access Point Map
bool handler(PDU&);
};
PCAPParser::PCAPParser(const string& pcapFilename, const string& filter) :
sniffer {pcapFilename, filter},
writer {"unique_beacons.pcap", PacketWriter::RADIOTAP} {
for (auto it = apMap.begin(); it != apMap.end(); it++) {
it->second.print();
}
}
bool PCAPParser::run() {
sniffer.sniff_loop( [this] (PDU& pdu) { return (bool) this->handler (pdu); } );
return true;
}
bool PCAPParser::handler(PDU& pdu) {
Dot11Beacon& beacon = pdu.rfind_pdu<Dot11Beacon>();
// An ESSID may span multiple BSSID's. Also, it's nice to keep track of what
// channels an AP has been on. Therefore, the combination of SSID, BSSID and
// channel is considered key.
const string& ssid = beacon.ssid();
const string& mac = beacon.addr3().to_string();
const unsigned channel = unsigned(beacon.ds_parameter_set());
const string key = ssid + mac + to_string(channel);
if (apMap.find(key) == apMap.end()) { // we've got a new one
Unit unit(beacon);
apMap[key] = unit;
writer.write(pdu);
} else {
apMap[key].incrementCount();
}
return true;
}
void PCAPParser::print() {
// Print the headers for the CSV output
cout << "SSID,BSSID,Current_channel,Count,Group_Cipher,Pairwise_Ciphers,Authentication_Suite" << endl;
// Ask each of the units to print themselves for the CSV output
for (auto it = apMap.begin(); it != apMap.end(); it++) {
it->second.print();
}
}
int main(int argc, char *argv[]) {
if(argc != 2) {
std::cout << "Usage: " << *argv << " <PCAP_FILE>\n";
return 1;
}
PCAPParser pcapParser(argv[1], "wlan type mgt subtype beacon");
pcapParser.run();
pcapParser.print();
}
Compile with:
g++ pcapreader.cpp -o pcapreader -O3 -std=c++11 -lpthread -ltins
The output is:
$ ./pcapreader capture.pcap
SSID,BSSID,Current_channel,Count,Group_Cipher, Pairwise_Ciphers,Authentication_Suite
MyWiFi,XX:XX:XX:XX:XX:XX,13,2,TKIP,TKIP;CCMP,PSK
...
...
Final note: if you open unique_beacons.pcap, you may find a lot of [Malformed Packet]. Apparently, a frame can still be successfully parsed if some of the tagged parameters are received wrongly. You could try to modify the code so that it only writes out frames to the pcap file that are completely intact.
tshark will print the "showname" attribute for text output only. You can control the output with a custom formatted by setting the gui.column.format preference. To print just SSID columns:
$ tshark -r capture.pcap -c 1 -T text -o 'gui.column.format:"SSID","%Cus:wlan.ssid"'

BouncyCastle J2ME RSA using custom keys

I would like to use BouncyCastle J2ME/RIM Crypto in my Blackberry Application.
The issue i'm having is that I would like to generate the public key for encryption from a C#.NET program that sends the key to the BlackBerry.
Is it possible to encrypt a message using a raw string? Also, do I need to know other common variable such as modulo etc? Apologies but i'm completely new to cryptography algorithms.
Do I need BouncyCastle for this or can the above be done with RIM Crypto?
Thanks,
Conor
I did it using bouncycastle, but with RIM Crypto is similar.
Follow the example. As you can see the keys are strings ... :
public CypherDecypherExample()
{
String plain ="a plain string";
String cipher = null;
String decipher = null;
byte [] byte_cipher = null;
byte [] byte_plain = null;
// key |-- 128 bit -->|-- 256 bit --->|
String key = "aaaaaaaaaaaaaaaacccccccccccccccc";
String iv = "bbbbbbbbbbbbbbbb";
System.out.println("bouncycastle.plain: " + plain);
try {
byte_cipher = encrypt(plain.getBytes(), key.getBytes(), iv.getBytes());
cipher = new String(byte_cipher);
System.out.println("bouncycastle.cipher: " + cipher);
} catch (Exception e) {
e.printStackTrace();
}
try {
byte_plain = decrypt(byte_cipher, key.getBytes(), iv.getBytes());
decipher = new String(byte_plain);
System.out.println("bouncycastle.decipher: " + decipher);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static byte[] cipherData(PaddedBufferedBlockCipher cipher, byte[] data)
throws Exception
{
String plain = new String(data);
System.out.println("bouncycastle.cipherData: " + plain);
int minSize = cipher.getOutputSize(data.length);
byte[] outBuf = new byte[minSize];
int length1 = cipher.processBytes(data, 0, data.length, outBuf, 0);
int length2 = cipher.doFinal(outBuf, length1);
int actualLength = length1 + length2;
byte[] result = new byte[actualLength];
System.arraycopy(outBuf, 0, result, 0, result.length);
System.out.println("bouncycastle.cipherData returning");
return result;
}
private static byte[] decrypt(byte[] cipher, byte[] key, byte[] iv) throws Exception
{
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher((BlockCipher) new CBCBlockCipher(
new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv);
aes.init(false, ivAndKey);
return cipherData(aes, cipher);
}
private static byte[] encrypt(byte[] plain, byte[] key, byte[] iv) throws Exception
{
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(
new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv);
aes.init(true, ivAndKey);
return cipherData(aes, plain);
}
An RSA public key consists of two components, not just one like I thought.
There is the Exponent and Modulus. These are both number but I pass them to the Blackberry from .NET client as Base64 strings and decode them into byte arrays when be used by the RIM Crypto function as they take Byte arrays as parameters.
byte[] exponent = Base64InputStream.decode("exponent base64 string");
byte[] modulus = Base64InputStream.decode("modulus base64 string");
NoCopyByteArrayOutputStream cipherUserData = new NoCopyByteArrayOutputStream();
RSACryptoSystem cryptoSystem = new RSACryptoSystem(1024);
// Create Public key using your variables from before
RSAPublicKey publicKey = new RSAPublicKey( cryptoSystem, exponent, modulus);
// Encryption engine objects
RSAEncryptorEngine eEngine = new RSAEncryptorEngine(publicKey);
PKCS1FormatterEngine fEngine = new PKCS1FormatterEngine(eEngine);
BlockEncryptor cryptoStream = new BlockEncryptor(fEngine, cipherUserData);
// Read the user data and encrypt while doing so. Remember, cryptoStream writes its data to
// cipherUserData so this is where the encrypted version of userData will end up.
cryptoStream.write( userData, 0, userData.length );
cryptoStream.close();
cipherUserData.close();
String encryptedUserData = new String(cipherUserData.toByteArray());
That's pretty much all there is too it folks, it's straightforward but it took me a long time to get this from the API docs :)
Important note
RSA is limited for encryption purposes in that you can only encrypt a message that <= key size.
That is 117 bytes for 1024 Bit RSA and 245 bytes for 2048 RSA. To encrypt larger messages the accepted way is to encrypt the message using AES or similar then encrypt the AES key with the RSA public key. You will the send the AES ciphertext and also the RSA ciphertext containing the key to decrypt the AES ciphertext.
What I have written above took days of tinkering and reading. I hope it helps somebody achieve their goal faster than that. :)

Resources