Is there a way to use commutative encryption in php? - java

I have used the encrypt and decrypt functions from this answer to implement message passing using Three-pass protocol with the Blowfish cipher.
And I tried using commutative ecryption/decryption. That is,
$tmp = encrypt($input, $key1);
$tmp = encrypt($tmp, $key2);
$tmp = decrypt($tmp, $key1);
$dec2 = decrypt($tmp, $key2);
But it does not work. I used a single key instead of 2 different keys and it works(has to!).
So there's no problem in the way I'm using these functions, but I simply cant get it working with two keys.
Am I doing something wrong? Is this not possible, or is there another way?
Or, is there a way I could do it in Java?
Edit: For those who don't understand the procedure, Three-pass protocol is a way to send encrypted messages without having to send the keys. So the procedure is
Sender encrypts with key1 and sends
Receiver encrypts with key2 and sends back
Sender decrypts with key1 and sends back
Receiver decrypts with key2 to get the original message
You can see that keys are not exchanged, but the message is sent only in encrypted form. That's the whole point.

Using the XOR function provided by a user in this thread
Encrypt/decrypt with XOR in PHP
function xor_this($string,$key) {
// Our plaintext/ciphertext
$text =$string;
// Our output text
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);)
{
for($j=0;($j<strlen($key) && $i<strlen($text));$j++,$i++)
{
$outText .= $text{$i} ^ $key{$j};
//echo 'i='.$i.', '.'j='.$j.', '.$outText{$i}.'<br />'; //for debugging
}
}
return $outText;
}
//The sender chooses a private encryption key s and a corresponding decryption key t. The sender encrypts the message m with the key s and sends the encrypted message E(s,m) to the receiver.
//The receiver chooses a private encryption key r and a corresponding decryption key q and super-encrypts the first message E(s,m) with the key r and sends the doubly encrypted message E(r,E(s,m)) back to the sender.
//The sender decrypts the second message with the key t. Because of the commutativity property described above D(t,E(r,E(s,m)))=E(r,m) which is the message encrypted with only the receiver's private key. The sender sends this to the receiver.
$senderkey=base64_encode('chicken');
$receiverkey=base64_encode('ardvark');
$itemwewanttoshare='hello darling';
echo'$itemwewanttoshare: '.$itemwewanttoshare.'<BR>';
$packet1=xor_this($itemwewanttoshare,$senderkey);
echo'$packet1: '.$packet1.'<BR>';
$packet2=xor_this($packet1,$receiverkey);
echo'$packet2: '.$packet2.'<BR>';
$packet3=xor_this($packet2,$senderkey);
echo'$packet3: '.$packet3.'<BR>';
$packet4=xor_this($packet3,$receiverkey);
echo'$packet4: '.$packet4.'<BR>';
You get this
$itemwewanttoshare: hello darling
$packet1: 1W6 TS>
$packet2: hNwRVtq|ing
$packet3: 1=&M"TS>
$packet4: hello darling
EDIT addition
I base64'd the key for simplicity. Use a key with more variation and the results will be more complicated.
use mcrypt_create_iv(40) to create your keys and you end up with something like this
$senderkey='<²#H[Ô\´(µÑ/KÀ®"熺¥ç|Ëvr%O›eu$nºbe';
$receiverkey='Øh\5PÀKO[ù¬òZH‰•Ê¬h/¥nëk¾ðéíPÄ"Uü';
which will change the output to
$itemwewanttoshare: hello darling
$packet1: T§ÞO'{§õ.®ÝF¥
$packet2: —?¶+¦6®½– þ
$packet3: «ý0Zpe¢ò"!<
$packet4: hello darling
Edit 2
Duskwuff brings up a good point. $itemwewanttoshare should be created by the system(program) and not be a user created item. This method could be used to establish a shared encryption key that both send and receiver could use to encrypt further communication. Sender would generate the key, and then that would be the itemwewanttoshare , thus allowing both sides to know the encryption key without passing it directly.

The WikiPedia article gives a hint at what can be used:
Sometimes the encryption function and decryption function are the same.
This is the case for stream ciphers like RC4 which create a long stream of pseudo-random data and simply XOR it with the data. XOR is commutative and it is easy to implement it in PHP:
$cipher = "arcfour";
$k1 = mcrypt_create_iv(256); // random
$k2 = mcrypt_create_iv(256); // random
$data = "some string";
$mode = "stream";
echo "key size: ".mcrypt_get_key_size($cipher, $mode)."\n"; // 256
echo "iv size: ".mcrypt_get_iv_size($cipher, $mode)."\n"; // 0
// Three-pass protocol property: D(d,E(k,E(e,m))) = E(k,m)
$c1 = mcrypt_encrypt($cipher, $k1, $data , $mode, "");
$c2 = mcrypt_encrypt($cipher, $k2, $data , $mode, "");
$c2 = mcrypt_encrypt($cipher, $k1, $c2 , $mode, "");
$c2 = mcrypt_decrypt($cipher, $k2, $c2 , $mode, "");
echo $c1 == $c2;
Block ciphers in CTR mode are also useable in the same way. This is an example of AES in CTR mode:
$cipher = "rijndael-128";
$k1 = mcrypt_create_iv(16); // random
$k2 = mcrypt_create_iv(16); // random
$iv1 = mcrypt_create_iv(16); // random
$iv2 = mcrypt_create_iv(16); // random
$data = "some string";
$mode = "ctr";
echo "key size: ".mcrypt_get_key_size($cipher, $mode)."\n";
echo "iv size: ".mcrypt_get_iv_size($cipher, $mode)."\n";
$c1 = mcrypt_encrypt($cipher, $k1, $data , $mode, $iv1);
$c2 = mcrypt_encrypt($cipher, $k2, $data , $mode, $iv2);
$c2 = mcrypt_encrypt($cipher, $k1, $c2 , $mode, $iv1);
$c2 = mcrypt_decrypt($cipher, $k2, $c2 , $mode, $iv2);
echo $c1 == $c2;

Related

Parse a JWT Token issued by a Java application, inside a python script

I have a Java Spring boot API that a user logs in and is issued a JWT token ( i cant change this code). I have a new python API that needs to parse the JWT to verify its been authenticated.
Java Code
import io.jsonwebtoken.Jwts;
private String secretKey = "CFB86D5E4DC4C11C6AFA9E5DF5AD9"
String jwt = Jwts.builder()
.setSubject(userByUsername.getUsername())
.setIssuedAt(now)
.setNotBefore(now)
.setIssuer("my-authenticator")
.setExpiration(new Date(System.currentTimeMillis() + (1000L * tokenMaxAge)))
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
Inside my python code i have
import jwt
token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY3NDUwMzE2NSwibmJmIjoxNjc0NTAzMTY1LCJpc3MiOiJ0ZXN0IiwiZXhwIjoxNjc0NTA2NzY1fQ.wPc98PTVmZKKUEBmuKZG3Z_fXrC7QLLpLE9BXHR3Sw4"
key = 'CFB86D5E4DC4C11C6AFA9E5DF5AD9'
jwt_options = {
'verify_signature': True,
'verify_exp': False,
'verify_nbf': False,
'verify_iat': True,
'verify_aud': False
}
parts = jwt.decode(token, key, algorithms="HS256", options=jwt_options)
print(parts)
If I set verify_signature = False everything works and i can parse the jwt. But I need to have this set to true. If I go to jwt.io the signature shows up as verified
I've tried playing around with encoding/decoding the string but Im not sure what I'm missing
I have tried decoding and encoding the key but havn't had success. The secret is the same in the java application and python application
ex1. key = b'CFB86D5E4DC4C11C6AFA9E5DF5AD9'
ex2. key = str(base64.urlsafe_b64decode(CFB86D5E4DC4C11C6AFA9E5DF5AD9), 'utf-8')
ex3. key = base64.urlsafe_b64decode(CFB86D5E4DC4C11C6AFA9E5DF5AD9)
ex4. key = base64.b64decode('CFB86D5E4DC4C11C6AFA9E5DF5AD9') # this gives binascii.Error: Invalid base64-encoded string: number of data characters (29) cannot be 1 more than a multiple of 4
Solution:
So I was able to solve my question but im not sure why it worked. The first consisted of setting my secret to a 256 character string ex. 73357638792F423F4428472B4B6250655368566D597133743677397A24432646 The next step was to encode it to UTF-8 and then b64encode it so:
jwt_options = {
'verify_signature': True,
'verify_exp': False,
'verify_nbf': False,
'verify_iat': True,
'verify_aud': False
}
signature_key = config.config.signature_key
signature_key = b64decode(signature_key.encode("utf-8"))
parts = jwt.decode(self.token, signature_key, algorithms=["HS256"], options=jwt_options)

My java Base64 results are not the same as php

I have previously posted a question related to this work link but I am posting a new one because the question is not completely resolved
I am working on converting the completed code into java with php.
It is a function that reads encrypted files, decrypts them by 16 bytes, makes them into a single string, and encodes them with base 64.
php is already on the server and running, and I have to use java to produce the same result.
If you decrypt the read file,
<?xml version="1.0" encoding="utf-8" ?>
<FileInfo>
...
<TextData> (text data) </TextData>
</FileInfo>
(image data)
It is in the format, and the text data in shows php and java exactly the same.
I am trying to encode the image data part into base64, but the result is different from php.
This is the part of the php code I have that decrypts and processes the read file
$fileContentArray = array(16);
$transContentArray = array(16);
$fileRead = fread($fp,16);
for($i = 0 ; $i < strlen($fileRead); $i++){
$fileContentArray[$i] = ord($fileRead[$i]);
}
$seed->SeedDecrypt($fileContentArray,$pdwRoundKey,$transContentArray);
$transStr = call_user_func_array("pack",array_merge(array("C16"),$transContentArray));
$mergeStr .= $transStr;
}
$dataExplode = explode("<TextData>",trim($mergeStr) );
$dataExplode1 = explode("</FileInfo>",trim($dataExplode[1]) );
$dataExplode2 = explode("</TextData>",$dataExplode1[0]);
$textData = iconv("EUC-KR","utf-8",$dataExplode2[0]);
$imageData = base64_encode(trim($dataExplode1[1]));
And this is the same part of the java code I wrote
byte[] fileContentArray=new byte[n];
for(int i=0;i<fileContentArray.length;i++){
fileContentArray[i]=mergeArr[nReadCur+i];
}
seed.SeedDecrypt(fileContentArray, pdwRoundKey, outbuf);
System.arraycopy(outbuf, 0, resultArr, nReadCur, outbuf.length);
nReadCur=nReadCur+fileContentArray.length;
p=p+fileContentArray.length;
if(p>=nFileSize){
fis.close();
break;
}
}//while
mergeStr=new String(resultArr,"MS949");
String[] dataExplode=mergeStr.trim().split("<TextData>");
String[] dataExplode1=dataExplode[1].trim().split("</FileInfo>");
String[] dataExplode2=dataExplode1[0].trim().split("</TextData>");
String textData = "";
String imageData = "";
textData=dataExplode2[0];
imageData=dataExplode1[1];
Encoder encoder=Base64.getEncoder();
Decoder decoder=Base64.getDecoder();
byte[] encArr=encoder.encode(imageData.trim().getBytes("MS949"));
imageData=new String(encArr,"MS949");
As a result of encoding image data into base64
php: R0lGODlhAwNLBPcAAAAAAAAAMwAAZgAAmQAAzAAA/wArAAArMwArZgArmQArzAAr/wBVAABVMwBVZgBVmQBVzABV/wCAAACAMwCAZgCAmQCAzACA/ ... VzpYirO0le55zF0=
java: R0lGODlhAwNLBD8AAAAAAAAAMwAAZgAAPwAAPwAAPwArAAArMwArZgArPwArPwArPwBVAABVMwBVZgBVPwBVPwBVPwA/AAA/MwA/ZgA/PwA/PwA/PwA/ ... DAQEAOz9GPz8/IXY=
As you can see, the result values are output differently.
Is there anything I'm missing? What should I do to make the result of java the same as php?
Also, MergeStr, who has read the file,
java:
GIF89aK? 3 f ? ? ? + +3 +f +? +? +? U U3 Uf U? U? U? ? ?3 ?f ?? ?? ?? ? ?3 챖 첌 ぬ ? ? ?3 ?f ??
...
J뇽杞H?*]苛⒢쬝쥻쒳뎁諾X...
A?h?~?0a?2$ #삁?d?Dd??e ...
...
WC ;홃?뿿!v
php:
GIF89aK? 3 f ? ?  + +3 +f +? +? + U U3 Uf U? U? U 3 f ? ?  ? ? 챖 첌 ぬ ? ? ? ? ? 螂 ?  3 f ? ? ...
A??~?a?$ #삁?d?Dd?e...
...
WC ;홃??v余퍙W:X뒽킉??
Like this, there is a new line text that I didn't put in, and there's a slight difference in result. Is this a simple difference in encoding? And does this affect the base64 conversion?
I tried encoding with UTF-8 and failed again,
and I used this code to load all bytes of the file at once
FileInputStream fis = new FileInputStream(tpf);
fis.read(mergeArr);
Java uses a little bit different encoding for base64 than PHP. You may use these helper functions to make them compatible to the Java version.
function base64url_encode($data)
{
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
function base64url_decode($data, $strict = false)
{
return base64_decode(strtr($data, '-_', '+/'), $strict);
}

Cannot sign data using private key, getting algorithm not supported by the key in swift

I have generated the private key in swift using the following code:
let publicKeyAttr: [NSObject: NSObject] = [
kSecAttrIsPermanent:true as NSObject,
kSecAttrApplicationTag:"com.xeoscript.app.RsaFromScrach.public2".data(using: String.Encoding.utf8)! as NSObject] // added this value
let privateKeyAttr: [NSObject: NSObject] = [
kSecAttrIsPermanent:true as NSObject,
kSecAttrApplicationTag:"com.xeoscript.app.RsaFromScrach.private2".data(using: String.Encoding.utf8)! as NSObject] // added this
var keyPairAttr = [NSObject: NSObject]()
keyPairAttr[kSecAttrKeyType] = kSecAttrKeyTypeRSA
keyPairAttr[kSecAttrKeySizeInBits] = 2048 as NSObject
keyPairAttr[kSecPublicKeyAttrs] = publicKeyAttr as NSObject
keyPairAttr[kSecPrivateKeyAttrs] = privateKeyAttr as NSObject
statusCode = SecKeyGeneratePair(keyPairAttr as CFDictionary, &publicKey, &privateKey)
And then I am using the private key to sign a piece of data, using the SecKeyAlgorithm.rsaEncryptionPKCS1 algorithm.
The code to sign is as follows:
public func sign(privateKey myPrivateKey: SecKey, value: String, base64EncodingOptions: Data.Base64EncodingOptions = []) throws -> String?
{
enum LoginErrors: Error {
case badUsername
case badPassword
}
guard #available(iOS 10.0, watchOS 3.0, tvOS 10.0, *) else {
return "Not available"
}
let data = value.data(using: .utf8)!
var error: Unmanaged<CFError>?
guard let signedData = SecKeyCreateSignature(myPrivateKey,
SecKeyAlgorithm.rsaEncryptionPKCS1,
data as CFData,
&error) as Data? else
{
return nil
}
return "(signedData.base64EncodedString())"
}
I am getting this exception:
[0] (null) "NSDescription" : "algid:encrypt:RSA:PKCS1: algorithm not supported by the key <SecKeyRef algorithm id: 1, key type: RSAPrivateKey, version: 4, block size: 2048 bits, addr: 0x280a0e5a0>"
SecKeyAlgorithm.rsaEncryptionPKCS1 is incorrect, this is attempting to use the RSA private key for hybrid encryption.
Instead pass something appropriate such as rsaSignatureDigestPKCS1v15SHA256, rsaSignatureDigestPSSSHA256 or one of the other options shown here.
Note, rsaSignatureDigestPKCS1v15SHA256 is deterministic.
Additionally, I would suggest using elliptic curve signature, RSA in 2020, however tempting, is the wrong choice.
There are so many gorgeous libs that support ECC now I wouldn't be using SecKit.

RSA cross platform b/w JAVA & Symbian

1) I am able to Encrypt and Decrypt with my app generated values in symbian with the below values
RInteger iE = RInteger::NewL(0x10001);
RInteger iN = RInteger::NewL(_L8("\xa3\x92\xb7\x34\x82\xbe\x7f\x4f\x8f\xbd\xfb\xd4\xf9\x80\x76\xe0\xa3\xf7\x42\x60\x8e\xe2\xa8\x6b\x76\x22\x67\x0e\x94\xeb\x9b\x3f\xd0\x73\x58\xe0\x23\xbb\x25\x53\x82\x56\x7b\x3e\x05\x57\xc9\x50\x3c\x2d\x6a\x09\x66\x3f\x49\xee\x41\x4c\x4b\x95\x1e\x7d\xb8\xd1\xc5\x40\x0d\xd0\xca\x72\xc8\xf6\x0d\x21\x4f\x63\xc1\x4c\x3b\x93\x94\x1f\x67\x5b\x70\x33\x07\xfd\x4e\x71\x59\x7f\x79\x9b\xd8\xf6\x3b\x35\xe1\x9a\xd3\x27\x43\xdb\x32\xcd\x7b\x78\x40\xd1\x0d\x40\x12\x53\xb7\x19\x66\xca\x5b\xf6\x26\x2a\xea\x4e\xef\xe4\xc8\x41"));
RInteger iD = RInteger::NewL(_L8("\x44\x21\x5a\xff\x9b\x29\x7f\x5b\x83\x32\x8d\x8f\x02\xb1\x18\x52\xae\xd8\xd1\x23\xe8\xbf\xcd\x88\x9c\xf6\xed\x57\xec\x7d\x49\xf7\xc5\x7a\x15\xdd\x9d\xe4\x58\x42\xb5\x3a\x12\x31\x1e\x06\x97\x8a\x3c\xd6\x69\xa1\x2a\x9e\x57\xcb\xce\x14\xda\x32\x6d\x35\xce\x61\x9e\xb2\xaf\x5c\x04\x13\xef\x68\x43\x7e\xe4\x98\xdc\x87\x2e\x7e\x38\x5f\xbd\xe9\x2e\xc1\xf1\x94\xf3\x95\x56\x56\xa4\x78\x26\x70\xa4\x1e\x10\x61\xe9\x45\x25\x1c\xed\xc6\xc0\x1e\xf6\x2c\xa0\x27\xee\x19\x0a\xed\x1c\x76\x33\xc8\x37\xde\x76\x25\x1c\x70\x77\xb1"));
2)Receiving N,E & D values from server then generating Public & Private keys .
(a) Encrypting with public key in app and decrypting in server side successfully.
but
(b) not able to decrypt with private key in my app getting KErrInvalidPadding.
(c) Even with server encrypted message not able to decrypt in app getting same error KErrInvalidPadding.
code:
RInteger iE = RInteger::NewL(0x10001);
RInteger iN = RInteger::NewL(_L8("\x89\x03\xfb\x6d\x15\xf3\x52\xed\x3b\x45\xad\xd3\x21\x6f\x63\x2f\x71\x39\x95\x4a\x56\x31\x33\x7a\xba\x7d\x64\x5e\xd3\x84\x82\xe3\xa8\x10\xb4\xdb\x26\xaa\xb4\xd1\xdf\x58\xc1\x47\x23\x0f\x0c\x75\x63\x1a\x3d\xd0\x55\x4b\x50\xde\x44\xe7\x9f\x4f\xcf\x20\x5c\x89\xfd\x3f\x80\xe0\xff\x8d\x16\xc2\xe9\xf5\x6e\xd3\xab\x17\x79\x53\xd5\x4c\x9c\x30\x35\x7d\x04\xe6\x77\xce\xdd\x99\x12\x90\x6e\xf8\xa0\x46\xd7\xb0\x18\x5b\x7f\x20\x22\xa8\xe4\x35\xb0\xc6\xec\xae\xf9\x3f\x08\x9f\xc3\xaa\x3f\x36\x77\x55\x0b\x5d\x84\x20\x46\xc7"));
RInteger iD = RInteger::NewL(_L8("\x35\xb9\x42\xff\x9d\xe8\xbf\xae\x57\x5c\x55\xf1\x00\x1e\x2d\xd4\xef\x5f\x75\xc3\x25\x12\xbb\xad\xb6\xab\xee\x0c\x24\x81\xc3\xd4\xc2\x14\x72\xe5\xaf\x3e\xa6\x11\xd8\xb2\x73\x6e\x92\x37\x97\x59\xfb\xd6\xd1\x3f\xfc\x01\xc1\x1e\xb6\x03\xdf\xfa\xaa\x2b\x75\x3c\xed\xc6\x8a\x02\x58\xb6\x8d\x6d\xf8\x34\x65\x03\xe3\x8a\x15\x37\xdf\x12\xa8\x18\xff\xce\xfa\x20\x20\xd6\xb7\x1a\x05\x6f\x2c\x04\x13\x58\x62\x94\xe9\xbc\x63\xc8\xd3\xd6\x06\x61\x44\x3e\xac\xe4\x98\x14\x63\xb1\xf7\x06\xaf\x1c\x16\xb6\x5b\x87\x87\x8e\x26\x01"));
TBuf8 <1024>aaaa;
TBuf8 <1024>aOut;
CRSAPublicKey *iPubKey = CRSAPublicKey::NewL(iN,iE);
CRSAPrivateKey *iPriKey = CRSAPrivateKeyStandard::NewL(iN,iD);
CRSAPKCS1v15Encryptor *iEncr = CRSAPKCS1v15Encryptor::NewL(*iPubKey);
CRSAPKCS1v15Decryptor *iDecry = CRSAPKCS1v15Decryptor::NewL(*iPriKey);
TRAPD(err3,iEncr->EncryptL(_L8("Hi"),aaaa));
TRAPD(err2,iDecry->DecryptL(aaaa,aOut)); <-KErrInvalidPadding = -11003;
how to solve this issue anybody suggest me with this.
what do i do
TInt len=iEncr->MaxOutputLength();
iEncr->EncryptL(_L8("Hi"),aaaa);
if (aaaa.Length()<len){
TBuf8<1> t;
t.SetLength(1);t[0]=0;
aaaa.Insert(0,t);
}

PHP Cryptography code explanation

public static function getEncryptedData($value){
if(!$value){return false;}
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, _PR_ACCOUNT_ACTIVATION_SECURE_KEY_, $text, MCRYPT_MODE_ECB, $iv);
return trim(base64_encode($crypttext)); //encode for cookie
}
I came across the above code in PHP.
I need to understand :
1. What is it doing?
2. How to do the same using Apache Shiro in Java?
/*Sets the function with the ability to be called globally without instantiating the object. Take one value into method through classname::getEncryptedData($value)*/
public static function getEncryptedData($value){
/*Checks to see if value is populated and an erroneous value hasn't been passed in such as null returns false if it has*/
if(!$value){return false;}
/* instantiated a local variable called text and populate it with the value $value*/
$text = $value;
/*as per the docs http://php.net/manual/en/function.mcrypt-get-iv-size.php gets the size of the iv and sets it in the var $iv_size*/
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
/*Creates an initialization vector as per http://uk3.php.net/manual/en/function.mcrypt-create-iv.php*/
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
/*Encrypt the data $text(from $value passed it) and store it in $crypttext */
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, _PR_ACCOUNT_ACTIVATION_SECURE_KEY_, $text, MCRYPT_MODE_ECB, $iv);
/*return a base64 encoded string with the whitespace trimmed from front and back*/
return trim(base64_encode($crypttext)); //encode for cookie
}
as for how to do it in java I dunno :-(

Categories

Resources