I'm new to Swift, now I just want to translate java xor encrypt/decrypt code to Swift, which is used for transactions between server and client. Below is the Java xor code:
public static String encrypt(String password, String key) {
if (password == null)
return "";
if (password.length() == 0)
return "";
BigInteger bi_passwd = new BigInteger(password.getBytes());
BigInteger bi_r0 = new BigInteger(key);
BigInteger bi_r1 = bi_r0.xor(bi_passwd);
return bi_r1.toString(16);
}
public static String decrypt(String encrypted, String key) {
if (encrypted == null)
return "";
if (encrypted.length() == 0)
return "";
BigInteger bi_confuse = new BigInteger(key);
try {
BigInteger bi_r1 = new BigInteger(encrypted, 16);
BigInteger bi_r0 = bi_r1.xor(bi_confuse);
return new String(bi_r0.toByteArray());
} catch (Exception e) {
return "";
}
}
And I've searched a lot about swift xor encryption and tried the answer in the links below:
XOR Encryption in Swift IOS
https://coderwall.com/p/timkvw/simple-xor-encryption-and-decryption-in-swift-playground-code
Swift Simple XOR Encryption
But all of them can't get the same encryted string compared with my java code, now my java code was live, and there's no way to change it.
I thought it might caused by the hexadecimal, but in swift, I can't find anywhere about swift xor hexadecimal.
So what I need is the swift code can get the exact same encrypted string as java code I've pasted, the encrypted string generated by my java client can be decrypted in my iOS client.
Thanks very much whoever can help me out of this! I've get into this a whole day!
Thanks again.
Solved, below is the code.
Based on the great work at https://github.com/lorentey/BigInt
func encrypt(str:String, key:BigUInt)->String
{
let value = BigUInt(str.data(using: String.Encoding.utf8)!)
let encrypt = key ^ value
return String(encrypt, radix: 16)
}
func decrypt(str:String, key:BigUInt)->String
{
let value = BigUInt(str, radix: 16)!
let decrypt = key ^ value
return String(data: decrypt.serialize(), encoding: String.Encoding.utf8)!
}
Thanks again for everyone whoever contributed to the the BigInt library, that's why the code looks so simple.
Related
I wrote a method that takes a JWT as a request and checks if the signature is valid.
This is the unit test:
#Test
public void isValid() {
final JwtValidator jwtValidator = JwtValidator.getInstance();
final boolean valid = jwtValidator.isValid("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c");
Assert.isTrue(valid);
}
and this is the code:
#SneakyThrows
public boolean isValid(String extractedToken) {
final String[] tokenParts = extractedToken.split(Pattern.quote("."));
String header = tokenParts[0];
String payload = tokenParts[1];
String signature = tokenParts[2];
final byte[] calcHmacSha256 = HMAC.calcHmacSha256("your-256-bit-secret".getBytes(), (header+"."+payload).getBytes());
final String s = Base64.getEncoder().encodeToString(calcHmacSha256);
System.out.println("'" + signature + "'.equals('"+s+"')");
return signature.equals(s);
}
The log prints two strings that differ only for 2 chars, so I feel like I'm close "but not quite" to make it work:
'SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'.equals('SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV/adQssw5c=')
There are of course hard coded values because the implementation isn't complete, but I'm using the example values in https://jwt.io/ for ease of use right now.
Thanks!
EDIT 1:
public class JwtValidatorTest {
#Test
public void isValid() {
byte[] header64 = Base64.getEncoder().encode("{\"alg\":\"HS256\",\"typ\":\"JWT\"}".getBytes());
byte[] payload64 = Base64.getEncoder().encode("{\"sub\":\"1234567890\",\"name\":\"John Doe\",\"iat\":1516239022}".getBytes());
final byte[] calcHmacSha256 = HMAC.calcHmacSha256("your-256-bit-secret".getBytes(), (header64+"."+payload64).getBytes());
final String signature64 = Base64.getEncoder().encodeToString(calcHmacSha256);
final String input = header64 + "." + payload64 + "." + signature64;
final JwtValidator jwtValidator = JwtValidator.getInstance();
final boolean valid = jwtValidator.isValid(input);
Assert.isTrue(valid);
}
}
The difference is just caused by the different encoding used here. You used Base64 encoding, but the original signature is Base64Url encoded. Base64Url encoding is, according to RFC7519, the standard encoding for JWT:
Each part contains a base64url-encoded value
Base64Url encoding has no padding (=) on the end and the characters + and / are replaced with -and _.
This code should solve the problem:
final String s = Base64.getUrlEncoder().withoutPadding().encodeToString(calcHmacSha256);
I m requirement is to convert below java encrypt code to flutter as i need to encrypt few fields value before sending to api.
Below is java encrypt code which i need to convert to java
public static String encrypt(String text, String algo, Key key) {
byte[] cipherText;
String output;
try {
if("RSA".equals(algo)) {
throw new IllegalArgumentException("Do not pass just algo pass with padding and blocking stuff!");
}
if(BuildConfig.DEBUG) {
Log.d(TAG, "encrypt in: "+text);
Log.d(TAG, "algo: "+algo);
Log.d(TAG, "key: "+key);
}
final Cipher cipher = Cipher.getInstance(algo);
if(algo.contains("AES")) {
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
} else {
cipher.init(Cipher.ENCRYPT_MODE, key);
}
cipherText = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8));
output = new String(Base64.encode(cipherText));
if(BuildConfig.DEBUG) {
Log.d(TAG, "encrypt out: "+output);
}
return output;
} catch (Exception e) {
Log.e(TAG, SDKConstants.STRING_ERROR + e, e);
return null;
}
}
char[] encPwd = Objects.requireNonNull(CryptoHelper.encrypt(Objects.requireNonNull(binding.textIPassword.getEditText()).getText().toString(), CryptoHelper.ALGO_FOR_RSA, key)).toCharArray();
Please help me in converting above java code to flutter as i need to encrypt one field before sending it to api call.
Any help is appreciated!
Just work through the Java line by line and figure out Dart equivalents. Use the other linked question as your guide. This should work (if I guessed the cipher correctly):
import 'package:pointycastle/export.dart';
String encrypt(String plainText, RSAPublicKey public) {
final plainBytes = utf8.encode(plainText) as Uint8List;
final cipher = PKCS1Encoding(RSAEngine())
..init(true, PublicKeyParameter<RSAPublicKey>(public));
final cipherBytes = cipher.process(plainBytes);
return base64Encode(cipherBytes);
}
I am trying to implement private key encryption within my application.
However, this key that I have to encrypt is of the List type and when I try to encrypt I get the following error:
Expected a value of type 'String', but got one of type 'List <int>'
how can I encrypt my key of type List correctly without getting errors so that I can later pass the parameter as type Uint8List to my method:
AccountEntity.account (account, Uint8List.fromList (privateKey));
this is my code:
var privateKey = await account.keyPair.extractPrivateKeyBytes();
privateKey = AesEncryptionDecryption
.encryptKey(
privateKey).bytes ;
final entity =
AccountEntity.account(account, Uint8List.fromList(privateKey));
while this is the class which contains the encryption methods, as API I used encrypt: ^ 5.0.1 from pubdev :
class AesEncryptionDecryption{
static final key = encrypt.Key.fromLength(32);
static final iv = encrypt.IV.fromLength(16);
static final encrypter = encrypt.Encrypter(encrypt.AES(key));
static encryptAES(text) {
final encrypted = encrypter.encrypt(text, iv: iv);
return encrypted;
}
static encryptKey(text) {
final encrypted = encrypter.encryptBytes(text, iv: iv);
return encrypted as List<int>;
}
static String decryptAES(String base64Text) {
print(base64Text);
String decrypted = encrypter.decrypt(
Encrypted.fromBase64(base64Text),
iv: iv,
);
print(decrypted);
return decrypted;
}
does anyone know how to help me? thank you very much
I have one small doubt as i am new to AES.
I encrypted a string using one certificate with some password lets say , 'xxx'.
Now i duplicated the certificate by changing the password of it.
When i try to decrypt the encrypted string with the duplicated cert, it says Bad padding exception.Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
However, when i use the original cert, it decrypts properly.
Could anyone please guide me on it?
public SecretKey retrieveKey(String password, byte[] certFile) throws Exception {
try {
String alias = null;
certPass = password;
char[] pass = certPass.toCharArray();
KeyStore keyStore = KeyStore.getInstance("jceks");
InputStream inputStream = new ByteArrayInputStream(certFile);
keyStore.load(inputStream, pass);
Enumeration enumeration = keyStore.aliases();
while (enumeration.hasMoreElements()) {
alias = (String) enumeration.nextElement();
}
Certificate cert = keyStore.getCertificate(alias);
Key key = cert.getPublicKey();
aesSecretKey = new SecretKeySpec(key.getEncoded(), algorithm);
byte[] encoded = aesSecretKey.getEncoded();
byte[] encryptionKey = Arrays.copyOfRange(encoded, encoded.length - 16, encoded.length);
aesSecretKey = new SecretKeySpec(encryptionKey, algorithm);
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw e;
}
return aesSecretKey;
}
You should use RSA to wrap / unwrap the AES key. The public key is not identical to the AES key, so the following code is certainly incorrect:
Key key = cert.getPublicKey();
aesSecretKey = new SecretKeySpec(key.getEncoded(), algorithm);
can anyone tell me how to validate the sha2+salt password while log in?? i am working in wicket framework and pg admin database, i was told to use hashing algorithm to create secure passwords. I just saw this example source code and i implemented it in my applciation and it just worked, but i dont know how to validate the salt+hash passwords while log in again. But i could able to validate the simple sha-2 paswwords but i couldn't and i don't know how to validate the sha2+salt password.
public class SHAExample {
public static void main(String[] args) throws NoSuchAlgorithmException {
String passwordToHash = "password";
String salt = getSalt();
String securePassword = get_SHA_1_SecurePassword(passwordToHash, salt);
System.out.println(securePassword);
securePassword = get_SHA_256_SecurePassword(passwordToHash, salt);
System.out.println(securePassword);
securePassword = get_SHA_384_SecurePassword(passwordToHash, salt);
System.out.println(securePassword);
securePassword = get_SHA_512_SecurePassword(passwordToHash, salt);
System.out.println(securePassword);
}
private static String get_SHA_1_SecurePassword(String passwordToHash, String salt)
{
String generatedPassword = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(salt.getBytes());
byte[] bytes = md.digest(passwordToHash.getBytes());
StringBuilder sb = new StringBuilder();
for(int i=0; i< bytes.length ;i++)
{
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
generatedPassword = sb.toString();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
return generatedPassword;
}
//Add salt
private static String getSalt() throws NoSuchAlgorithmException
{
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[16];
sr.nextBytes(salt);
return salt.toString();
}
}
Output:
e4c53afeaa7a08b1f27022abd443688c37981bc4
You have to do the same steps as you did when storing the password hash. That means you calculate the hash of the entered password with the same algorithm and the same salt you used before, then you can compare the hashes.
Be aware that the SHA* hash algorithms are not secure to hash passwords, because they are ways too fast and can be brute-forced too easily. Instead you switch to a slow key-derivation function like BCrypt or PBKDF2.