I am having trouble using phpseclib to verify the signature used in the example documented in appendix A.2.2 of https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-signature-38. The values used as modulus, exponent, signature and tobesigned come from the appendix of the specification. The signature does verify when using .NET and several implementations of the specification have been created so it I assume the inputs are valid. I have no previous experience with phpseclib, had to guess at how to load the key, and find the documentation minimalistic so your help would be much appreciated!
// per guzmar converts the encoding used in the ietf specification to a string
function cpim_base64url_decode($data) {
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4,
'=', STR_PAD_RIGHT));
}
$rsa = new Crypt_RSA();
$publicKeyUrlEncoded = "ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ";
$exponentUrlEncoded = "AQAB";
$publicKeyString = base64url_decode($publicKeyUrlEncoded);
$exponentString = base64url_decode($exponentUrlEncoded);
$pk = array(
'e' => new Math_BigInteger($exponentString, -256),
'n' => new Math_BigInteger($publicKeyString, -256)
);
$rsa->setHash('sha256');
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$tobesignedString = 'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ';
$signatureUrlEncoded = "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw";
$signatureString = base64url_decode($signatureUrlEncoded);
$keyloadResult = $rsa->loadKey($pk, CRYPT_RSA_PUBLIC_FORMAT_RAW);
$result = $rsa->verify($tobesignedString, $signatureString) ? 'verified' : 'unverified';
The problem is that n and possibly the private exponent are negative.
Modular arithmetic doesn't work with a negative modulus. It depends on the library if this is a problem. The crypto-specific BN_ libs of OpenSSL are only for positive values, but other libraries that use a two complement implementation - i.e. with negative values such as Java have the same issues.
You could just always prefix a zero valued byte for any number used within RSA. RSA is based on modular arithmetic and doesn't use negative values for any of the components of a key.
Related
I'm looking into using twofish to encrypt strings of data. Before trusting my precious data to an unknown library I wish to verify that it agrees with the known answer tests published on Bruce Schneier's website.
To my dismay I tried three twofish implementations and found none that agree with the KAT. This leads me to believe that I'm doing something wrong and I'm wondering if someone could tell me what it is.
I've made sure the mode is the same (CBC), the key length is the same (128bits) and the iv/key/pt values are the same. Is there an additional parameter in play for twofish encryption?
Here are the first two test entries from CBC_E_M.txt from the KAT archive:
I=0
KEY=00000000000000000000000000000000
IV=00000000000000000000000000000000
PT=00000000000000000000000000000000
CT=3CC3B181E1495D0495D652B66921DA0F
I=1
KEY=3CC3B181E1495D0495D652B66921DA0F
IV=3CC3B181E1495D0495D652B66921DA0F
PT=BE938D30FAB43B71F2E114E9C0529299
CT=695250B109C6F71D410AC38B0BBDA3D2
I interpret these to be in hex, therefore 16bytes=128bits long.
I tried using the following twofish implementations:
ruby: https://github.com/mcarpenter/twofish.rb
JS: https://github.com/ryanofsky/twofish/
online: http://twofish.online-domain-tools.com/
All three give the same CT for the first test, namely (hex encoded)
9f589f5cf6122c32b6bfec2f2ae8c35a
So far so good, except it does not agree with CT0 in the KAT...
For the second test the ruby library and the online tool give:
f84268f0293adf4d24e27194911a24c
While the js library gives:
fd803b310bb5388ddb76d5faf9e23dbe
And neither of these agrees with CT1 in the KAT.
Am I doing something wrong here? Any help greatly appreciated.
The online tool is easy to use, just be sure to select HEX for the key and input text. Here is the ruby code I used to generate these values (it's necessary to check out each library for this to work):
def twofish_encrypt(iv_hex, key_hex, data_hex)
iv = iv_hex.gsub(/ /, "").scan(/../).map { |x| x.hex.chr }.join
key = key_hex.gsub(/ /, "").scan(/../).map { |x| x.hex.chr }.join
data = data_hex.gsub(/ /, "").scan(/../).map { |x| x.hex.chr }.join
tf = Twofish.new(key, :mode => :cbc, :padding => :none)
tf.iv = iv
enc_data = tf.encrypt(data)
enc_data.each_byte.map { |b| b.to_s(16) }.join
end
ct0 = twofish_encrypt("00000000000000000000000000000000",
"00000000000000000000000000000000",
"00000000000000000000000000000000")
puts "ct0: #{ct0}"
ct1 = twofish_encrypt("3CC3B181E1495D0495D652B66921DA0F",
"3CC3B181E1495D0495D652B66921DA0F",
"BE938D30FAB43B71F2E114E9C0529299")
puts "ct1: #{ct1}"
function twofish_encrypt(iv_hex, key_hex, data_hex) {
var iv = new BinData()
iv.setHexNibbles(iv_hex)
iv.setlength(16*8)
binkey = new BinData()
binkey.setHexNibbles(key_hex)
binkey.setlength(16*8)
key = new TwoFish.Key(binkey);
data = new BinData()
data.setHexNibbles(data_hex)
data.setlength(16*8)
cipher = new TwoFish.Cipher(TwoFish.MODE_CBC, iv);
enc_data = TwoFish.Encrypt(cipher, key, data);
return enc_data.getHexNibbles(32);
}
var ct0 = twofish_encrypt("00000000000000000000000000000000",
"00000000000000000000000000000000",
"00000000000000000000000000000000");
console.log("ct0: " + ct0);
var ct1 = twofish_encrypt("3CC3B181E1495D0495D652B66921DA0F",
"3CC3B181E1495D0495D652B66921DA0F",
"BE938D30FAB43B71F2E114E9C0529299");
console.log("ct1: " + ct1);
The header of the CBC_E_M.txt file reads:
Cipher Block Chaining (CBC) Mode - ENCRYPTION
Monte Carlo Test
The confusion can be explained by this description; from the NIST description of the Monte Carlo Tests:
Each Monte Carlo Test consists of four million cycles through the candidate algorithm implementation. These cycles are divided into four hundred groups of 10,000 iterations each. Each iteration consists of processing an input block through the candidate algorithm, resulting in an output block. At the 10,000th cycle in an iteration, new values are assigned to the variables needed for the next iteration. The results of each 10,000th encryption or decryption cycle are recorded and included by the submitter in the appropriate file.
So what you get in the text file is 400 results, each representing 10,000 iterations where each input of an iteration depends on the output of the previous iterations. This is obviously not the same as a single encryption. Monte Carlo tests are basically performing many tests using randomized input; in this case a high number of block cipher encrypts are used to perform the randomization.
To test if your CBC code is correct, just use any of the other test vectors (not the Monte Carlo ones) and assume an all zero IV. In that case a single block (ECB) encrypt has the identical outcome of CBC mode. This also works for the ever more popular CTR mode.
The initial 9f589f5cf6122c32b6bfec2f2ae8c35a value that you found is correct for a 128 bit all zero key, IV and plaintext. The f84268f0293adf4d24e27194911a24c value is correct as well.
There is certainly something wrong with your hex encoder, your result is even not of the correct size for that value (what happens with leading zero's of the hex encodings?). Given the results and code, I would definitely take a look at your encoding / decoding functions.
I am migrating on RSACng for new version release from RSACryptoServiceProvider. However, as RSACryptoserviceProvider that is CAPI uses Little Endian Architecture and RSACng that is CNG API is using Big Endian Architecture, question is how can i decrypt the data using CNG Api that is previously encrypted using RSACryptoService provider (CAPI)?
I have already tried Array.reverse(cypherText) and tried to decrypt using CNG Api, but it is throwing the error, 'The parameter is incorrect'.
I have also tried the approach of decrypting half the cypher text because CNG API is using RSAEncryptionPadding.OaepSHA512 padding whereas CAPI uses OAEP padding.
My RSACryptoServiceProvider class is as below:-
public static void EncryptWithSystemKeyRSACryptoService(byte[]
plainBytes, bool representsUnicodeString, out string cypherText)
{
CspParameters cp = new CspParameters();
cp.KeyContainerName = regValue.ToString();
cp.Flags = CspProviderFlags.UseMachineKeyStore;
cp.KeyNumber = (int)KeyNumber.Exchange;
byte[] encBlockData=null;
using (RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider(cp))
{
res = CryptResult.GeneralError;
int keysize = rsaCSP.KeySize;
//This encrypts data and uses FOAEP padding
encBlockData = rsaCSP.Encrypt(plainBytes, true);
}
//Should i have to reverse the Byte order?
// I am doing Array.reverse for encrypted data as it follows little endian architecture and CNG Api follows Big Endian architecture
Array.Reverse(encBlockData);
cypherText = BitConverter.ToString(encBlockData );
cypherText = cypherText.Replace("-", "");
cypherText = cypherText.ToLower();
}
This is how i encrypt data with RSACryptoservice Provider (CAPI)
My RSACng class is as below :-
//I am calling this to use RSACng API to get private keys
private static byte[] SetPrivateAndPublicKeysAndDecrypt(byte[] cyphertext)
{
cp.KeyContainerName = regValue.ToString();
cp.Flags = CspProviderFlags.UseMachineKeyStore;
cp.KeyNumber = (int)KeyNumber.Exchange;
using (RSACryptoServiceProvider rsaCSP = new
RSACryptoServiceProvider(cp))
{
res = CryptResult.GeneralError;
keysize = rsaCSP.KeySize;
q = rsaCSP.ExportCspBlob(false);
RSAp = rsaCSP.ExportParameters(true);
}
//created cngKey
cngKey = CngKey.Import(q, CngKeyBlobFormat.GenericPublicBlob);
//created RSACng instance
RSACng rsacng = new RSACng(cngKey)
{
KeySize = keysize
};
rsacng.ImportParameters(RSAp);
//Decrypt using RSACng API using OAEPSHA512 padding
var plainText= crypto.Decrypt(cyphertext, RSAEncryptionPadding.OaepSHA512);
return plainText;
}
Expected result should be-> plainText successfully decrypted
Actual Resul-> Exception caught-> 'The parameter is incorrect'.
RSA ciphertext is defined to use statically sized, unsigned, big endian encoding in PKCS#1 (which specifies PKCS#1 v1.5 RSA encryption and OAEP encryption as implemented by most libraries). The function is called I2OSP within that standard, and the ciphertext should have the same size (in full bytes) as the key size. If it isn't big endian, then it does not conform to RSA / OAEP, in other words.
The same goes for normal ASN.1 encoded keys: they use dynamically sized, signed, big endian encoding according to DER (distinguished encoding rules). Those keys are defined in PKCS#1, PKCS#8 and X.509 standards, although they may also be embedded in a PKCS#12 compatible key store - for instance. Sometimes the keys are then PEM encoded as well to make them compatible with protocols that require text rather than binary.
So you should never have to reverse ciphertext or keys that use one of the standard encodings. That the calculations are performed internally on little endian (or not) is of no concern. This is true for about every modern cipher or other cryptographic primitive; the input / output is simply defined in bytes with a specific order, not numbers. Only very low level functions may possibly operate on e.g. words, which muddles the problem (but you won't find that in the MS API's).
Only Microsofts own proprietary (lame) key encodings may use little endian.
bartonjs is of course correct in the comments; you need to match the padding methods, and the default hash to be used for OAEP (or rather, the mask generation function MGF1 within OAEP) is SHA-1. There are plenty of other pitfalls to avoid, such as performing correct encoding / decoding of plaintext / ciphertext.
I am reading an encrypted string from an application in xcode and I have to write a function that uses RSA decryption to decode and display the message.
I am completely lost on where to begin with this.
I have Openssl complied in xcode and I am using the openssl/rsa.h file.
I am trying to use the function:
RSA_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding);
But then I'd read somewhere on the Openssl main site that the function just returns a number and not the actual string. I also have no idea what paramenters to pass through.
The only reference I have found is the openssl/rsa.h file and looking at the functions it contains.
I've tried doing some research the past couple hours but I have no found any answers.
I was wondering if there is a simple function that I can pass my encrypted string and my private key (using a file or hardcoded) and it can return the decrypted string?
If not is there a guide on how to use Openssl with Objective C programming?
Please let me know if you need more information on the issue.
Thank you in advance.
You may want to look Apple's example which uses security transforms (this avoids openssl) in their Security Overview.
With a bit of luck you can do things with apple transforms and go with that programme.
If not - or if for some reason you really want to use openssl; then the openssl source contains the example file openssl-0.9.8t/apps/rsa.c which pretty much allows for selective cut-and-paste to make things work.
Doing man RSA_private_decrypt from the command line will show you the manual page (or from within Xcode to the man page). Or see http://www.openssl.org/docs/crypto/RSA_public_encrypt.html.
Example use for the above:
unsigned char in[] = { 1, 2, ... byte array to decrypt };
// size of that in byte array
int inlen = sizeof(in);
// output buffer size depends on the key type.
char * out = malloc(RSA_size(rsa));
int e = RSA_private_decrypt(inlen, in, out, rsa, RSA_PKCS1_PADDING);
where padding is one of the values from the man-page.
The value of rsa is a bit more complex to initialise as this is where you set up your keys and what not. Check the above rsa.c file for examples of various ways of filling it - it normally boils down to something like:
EVP_PKEY *pkey = load_key( ... , password,... );
rsa = EVP_PKEY_get1_RSA(pkey);
where load_key is borrowed from the app examples of openssl.
I use RSACryptoServiceProvider to encrypt some small blocks of data. For the solution I'm working on, it's important that if the same piece of source data is encrypted twice with the same public key, the result (the encrypted block of data) is not the same.
I have checked this with an example and it worked like I hoped. My question is now, if this behaviour is by design and guaranteed or if I have to add some random part to the source data for guaranteeing that data blocks with the same data can not be matched anymore after encryption.
Here is the example:
byte[] data=new byte[]{1,7,8,3,4,5};
RSACryptoServiceProvider encrypter = cert.PublicKey.Key as RSACryptoServiceProvider;
byte[] encryptedData = encrypter.Encrypt(data,true);
// encryptedData has always other values in, although the source data is always
// 1,7,8,3,4,5 and the certificate is always the same (loaded from disk)
The concrete question is for .net but maybe the answer can be given in general for all RSA-implementations if it is by design?
The text-book RSA encryption algorithm is deterministic:
ciphertext = plaintext ^ encryption-exponent mod modulus
(Here ^ is integer exponentiation, mod the remainder operation.)
But as you remarked, this does not provide a good security guarantee, as an attacker which can guess the plaintext can simply verify this guess by encrypting it himself and comparing the results.
For this reason, the official RSA specifications (and also all implementations used in practice) include some (partly random) padding, so we don't actually encrypt plaintext, but pad(plaintext):
ciphertext = pad(plaintext) ^ encryption-exponent mod modulus
Decryption:
plaintext = unpad( ciphertext ^ decryption-exponent mod modulus )
Only with this padding RSA is actually a secure encryption scheme.
A similar padding is also used for RSA signatures, to avoid easy forging of signatures.
when I call getwork on my bitcoind server, I get the following:
./bitcoind getwork
{
"midstate" : "695d56ae173bbd0fd5f51d8f7753438b940b7cdd61eb62039036acd1af5e51e3",
"data" : "000000013d9dcbbc2d120137c5b1cb1da96bd45b249fd1014ae2c2b400001511000000009726fba001940ebb5c04adc4450bdc0c20b50db44951d9ca22fc5e75d51d501f4deec2711a1d932f00000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000",
"hash1" : "00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000",
"target" : "00000000000000000000000000000000000000000000002f931d000000000000"
}
This protocol does not seem to be documented. How do I compute the hash from this data. I think that this data is in little endian. So the first step is to convert everything to big endian? Once that is done, I calculate the sha256 of the data. The data can be divided in two chuncks of 64 bytes each. The hash of the first chuck is given by midstate and therefore does not have to be computed.
I must therefore hash the chunck #2 with sha256, using the midstate as the initial hash values. Once that is done, I end up with a hash of chunk 2, which is 32 bytes. I calculate the hash of this chunk one more time to get a final hash.
Then, do I convert everything to little endian and submit the work?
What is hash1 used for?
The hash calculation is documented at Block hashing algorithm.
Start there for the relatively simple basics. The basic data structures are documented in Protocol specification - Bitcoin Wiki. Note that the protocol definition (and the definition of work) more or less assumes that SHA-256 hashes are 256-bit little-endian values, rather than big-endian as the standard implies. See also
Getwork is more complicated and runs into more serious endian/byte ordering confusion.
First note that the getwork API is optimized to speed up the initial steps of mining.
The midstate and hash1 values are for these performance optimizations and can be ignored. Just look at the "data".
And when a standard sha256 implementation is used, only the first 80 bytes (160 hex characters) of the "data" are hashed.
Unfortunately, the JSON data presented in the getwork data structure has different endian characteristics than what is needed for hashing in the block example above.
They all say to go to the source for the answer, but the C++ source can be big and confusing. A simple alternative is the poold.py code. There is discussion of it here: New mining pool for testing. You only need to look at the first few lines of the "checkwork" routine, and the "bufreverse" and "bytereverse" functions, to get the byte ordering right. In the end it is just a matter of doing a reversal of the bytes in each 32-bit segment of the data. Yes - very odd. But endian issues are tricky and can end up that way....
Some other helpful information on the way "getwork" works can be found in discussions at:
Do I understand header hashing?
Stupid newbie question about the nonce
Note that finding the signal to noise in the original Bitcoin forum is getting very hard, and there is currently an Area51 proposal for a StackExchange site for Bitcoin and Crypto Currency in general. Come join us!
It sounds right, there is a script in javascript that do calculate the hash but I do not fully understand it so I don't know, maybe you understand it better if you look.
this.tryHash = function(midstate, half, data, hash1, target, nonce){
data[3] = nonce;
this.sha.reset();
var h0 = this.sha.update(midstate, data).state; // compute first hash
for (var i = 0; i < 8; i++) hash1[i] = h0[i]; // place it in the h1 holder
this.sha.reset(); // reset to initial state
var h = this.sha.update(hash1).state; // compute final hash
if (h[7] == 0) {
var ret = [];
for (var i = 0; i < half.length; i++)
ret.push(half[i]);
for (var i = 0; i < data.length; i++)
ret.push(data[i]);
return ret;
} else return null;
};
SOURCE: https://github.com/jwhitehorn/jsMiner/blob/4fcdd9042a69b309035dfe9c9ddf716119831a16/engine.js#L149-165
Frankly speaking
Bitcoin block hashing algorithm is not officially described by any source.
"
The hash calculation is documented at Block hashing algorithm.
"
should read
The hash calculation is "described" at Block hashing algorithm.
en.bitcoin.it/wiki/Block_hashing_algorithm
btw the example code in PHP comes with a bug (typo)
the example code in Python generates errors when run by Python3.3 for Windows XP 32
(missing support for string.decode)