Encryption compatibility between Obj-C and VB.Net - ios

There are about 100,000 different possible ways to encrypt a string. Using standards like AES, CBC, and PKCS7 make things easier - but there are still problems with IVs. Salts, Encoding, etc. (As noted on www.Crypto.Stackexchange.com)
For my iOS project (Obj-C), I'm using the FBEncryptor project which is an easy and well documented way to encrypt strings. However, I need code that will be able to decrypt that iOS AES string generated by FBEncryptor on a Windows platform - preferably VB.NET.
I have yet to find another project for VB.NET that is compatible with FBEncryptor.
Does anyone know of any VB.NET encryption projects that work with FBEncryptor? If not, then what do I need to do to make the Rijndael Managed library (provided by Microsoft) work with FBEncryptor?
My VB.NET Code using Rijndael Managed:
Imports System.Security
Imports System.Security.Cryptography
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Text.RegularExpressions
Imports System.Text
Module Encrypt2
Public saltBytes As Byte()
Dim hashAlgorithm As String = "SHA1"
Public Sub GenerateSalt()
' Define min and max salt sizes.
Dim minSaltSize As Integer
Dim maxSaltSize As Integer
minSaltSize = 8
maxSaltSize = 8
' Generate a random number for the size of the salt.
Dim random As Random
random = New Random()
Dim saltSize As Integer
saltSize = random.Next(minSaltSize, maxSaltSize)
' Allocate a byte array, which will hold the salt.
saltBytes = New Byte(saltSize - 1) {}
' Initialize a random number generator.
Dim rng As RNGCryptoServiceProvider
rng = New RNGCryptoServiceProvider()
' Fill the salt with cryptographically strong byte values.
rng.GetNonZeroBytes(saltBytes)
End Sub
Public Function Encrypt(ByVal plainText As String, ByVal keyword As String) As String
Dim hashAlgorithm As String = "SHA1"
Dim passwordIterations As Integer = 128
Dim initVector As String = "#7781157e2629b09"
Dim keySize As Integer = 256
Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(initVector)
Dim plainTextBytes As Byte() = Encoding.ASCII.GetBytes(plainText)
GenerateSalt()
Dim password As New Rfc2898DeriveBytes(keyword, saltBytes, passwordIterations)
Dim keyBytes As Byte() = password.GetBytes(keySize \ 8)
Dim symmetricKey As New RijndaelManaged()
symmetricKey.Mode = CipherMode.CBC
Dim encryptor As ICryptoTransform = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes)
Dim memoryStream As New MemoryStream()
Dim cryptoStream As New CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length)
cryptoStream.FlushFinalBlock()
Dim cipherTextBytes As Byte() = memoryStream.ToArray()
memoryStream.Close()
cryptoStream.Clear()
Dim cipherText As String = Convert.ToBase64String(cipherTextBytes)
Return (cipherText)
End Function
Public Function Decrypt(ByVal cipherText As String, ByVal keyword As String) As String
Dim hashAlgorithm As String = "SHA1"
Dim passwordIterations As Integer = 128
Dim initVector As String = "#7781157e2629b09"
Dim keySize As Integer = 256
' Convert strings defining encryption key characteristics into Byte
' arrays. Let us assume that strings only contain ASCII codes.
' If strings include Unicode characters, use Unicode, UTF7, or UTF8
' encoding
Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(initVector)
' Convert the Ciphertext into a Byte array
Dim cipherTextBytes As Byte() = Encoding.ASCII.GetBytes(cipherText)
' First we must create a password, from which the key will be
' derived. This password will be generated from the specified
' passphrase and salt value. The password will be created using
' the specified hash algorithm. Password creation can be done in
' several iterations
GenerateSalt()
Dim password As New Rfc2898DeriveBytes(keyword, saltBytes, passwordIterations)
' Use the password to generate pseudo-random bytes for the encryption
' key. Specify the size of the key in bytes (instead of bits)
Dim keyBytes As Byte() = password.GetBytes(keySize \ 8)
' Create uninitialized Rijndael encryption object
Dim symmetricKey As New RijndaelManaged()
' It is reasonable to set encryption mode to Cipher Block Chaining
' (CBC). Use default options for other symmetric key parameters.
symmetricKey.Mode = CipherMode.CBC
' Generate decryptor from the existing key bytes and initialization
' vector. Key size will be defined based on the number of the key
'bytes
Dim decryptor As ICryptoTransform = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes)
' Define memory stream which will be used to hold encrypted data.
Dim memoryStream As New MemoryStream(cipherTextBytes)
' Define cryptographic stream (always user Read mode for encryption).
Dim cryptoStream As New CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)
' Since at this point we don't know what the size of decrypted data
' will be, allocate the buffer long enough to hold ciphertext;
' plaintext is never longer than ciphertext
Dim plainTextBytes As Byte() = New Byte(cipherTextBytes.Length - 1) {}
' Start decrypting.
Dim decryptedByteCount As Integer = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length)
' Close both streams
memoryStream.Close()
cryptoStream.Close()
' Convert decrypted data into a string
' Let us assume that the original plaintext string was UTF8-Encoded.
Dim plainText As String = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount)
' Return the decrypted string
Return (plainText)
End Function
End Module
You'll notice that the IV is static and that the password iterations are low. This is because I'm not sure how to generate the IV in the same method as FBEncryptor. You may also notice that when attempting to decrypt, there are problems with the byte length.
Any help will be appreciated! Thanks!

One note. I looked in FBEncryptor. It uses some bad practices. So, if security is important for you I would recommend read up a little bit more regarding that and choose another code which does encryption (or write it on your own).
FBEncryptor does following for encryption
a) Convert string to byte array (based on UTF8 encoding)
b) Convert key to byte array (based on UTF encoding).
c) Copy only first 16 bytes of key
d) Create IV which is 16 butes of 0x00
e) Encrypt byte array from item a) using AES/CBC/PKCS7Padding with IV created in d)
f) The resulting encrypted data is converted to Base64
And it does following for decryption
a) Convert encrypt string from Base64 to byte array
b) Convert key to byte array (based on UTF encoding).
c) Copy only first 16 bytes of key
d) Create IV which is 16 butes of 0x00
e) Decrypt byte array from item a) using AES/CBC/PKCS7Padding with IV created in d)
f) Convert encrypted data from e) to a string using UTF8 encoding
You should do exactly the same thing in VB.NET. I think you have almost all parts
- You will need to drop all SHA1 and salt related stuff and use equivalent of step b).
And you will need to research PKCS7Padding for VB.NET

Related

How to flip an integer that represents a 8-digit hex string in Lua?

In my Lua script, I have a variable that stores an integer found from some function that represents a hex string. I want to flip it so that, for example, if it has a value of 0x006E57E8, it will become 0x8E75E600. How do I do it in Lua?
As an alternative to Skriptunoff's very concise & readable function, here's a function doing it using bit ops:
function reverse_nibbles(int)
res = 0
for i = 0, 7 do
res = res | (((int >> (4*i)) & 0xF) << (28 - 4*i))
end
return res
end
This won't create a garbage string (and would hopefully be faster). You might want to hand-unroll the loop.

CryptographicException: ASN1 corrupted data in F#

I want to hash a message with the RSA class using f#.
Currently, I managed to create these few lines using the default randomly generated key pair.
let rsa = RSA.Create()
let dataInBytes = System.Text.Encoding.UTF8.GetBytes ("Message to be hashed.")
let bytes = rsa.SignData(dataInBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
In order to use my own private/public key pair I want to use .ImportPkcs8PrivateKey(). My code is:
let privKey = System.IO.File.ReadAllText #"C:\Users\User\Documents\FSharp\privkey.pem";;
val privKey: string =
"-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASC"+[1671 chars]
let convertFromBase64ToBytes (input: string) =
let str = match input.Length % 4 with
| 1 -> input.Substring (1, input.Length - 1)
| 2 -> input + string "=="
| 3 -> input + string "="
| _ -> input
let strReplaced = str
.Replace("-", "+")
.Replace("_", "/")
System.Convert.FromBase64String strReplaced
let privKeyBytes = convertFromBase64ToBytes privKey
> rsa.ImportPkcs8PrivateKey (privKeyBytes);;
but it throws me the error:
System.Security.Cryptography.CryptographicException: ASN1 corrupted data.
---> System.Formats.Asn1.AsnContentException: The encoded length exceeds the maximum supported by this library (Int32.MaxValue).
at System.Formats.Asn1.AsnDecoder.ReadLength(ReadOnlySpan`1 source, AsnEncodingRules ruleSet, Int32& bytesConsumed)
at System.Formats.Asn1.AsnDecoder.ReadEncodedValue(ReadOnlySpan`1 source, AsnEncodingRules ruleSet, Int32& contentOffset, Int32& contentLength, Int32& bytesConsumed)
at System.Security.Cryptography.CngPkcs8.ImportPkcs8PrivateKey(ReadOnlySpan`1 source, Int32& bytesRead)
--- End of inner exception stack trace ---
at System.Security.Cryptography.CngPkcs8.ImportPkcs8PrivateKey(ReadOnlySpan`1 source, Int32& bytesRead)
at System.Security.Cryptography.RSAImplementation.RSACng.ImportPkcs8PrivateKey(ReadOnlySpan`1 source, Int32& bytesRead)
at <StartupCode$FSI_0012>.$FSI_0012.main#() in C:\Users\User\PowerShell\stdin:line 26
Stopped due to error
What am I missing?
ImportPkcs8PrivateKey() expects a DER encoded key in PKCS#8 format. The posted key has the correct format, but is PEM encoded. The conversion from PEM to DER consists of removing the header, footer, all line breaks, and Base64 decoding the rest:
...
let derB64 = privKey.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("\r\n", "")
let privKeyBytes = Convert.FromBase64String derB64
rsa.ImportPkcs8PrivateKey privKeyBytes
...
As of .NET 5, the ImportFromPem() method is available, which can directly import the PEM encoded key.
The convertFromBase64ToBytes() method converts Base64url encoded data to Base64 encoded data and then performs a Base64 decoding.
Since PEM encoded keys are Base64 encoded (and not Base64url encoded) this method is actually not necessary, instead Convert.FromBase64String() can be applied directly (if it is used anyway, it has no effect, because already Base64 encoded data is not changed).
The format that begins / ends with -----BEGIN XXX----- and ends with a similar line is called PEM encoding.
You are missing the fact that the base 64 also contains newlines and - etc. (so the length calculation fails). You should not have to pad with = symbols - those are mandatory for PEM. Similarly, PEM uses normal base 64, so there is no need to do anything with - or _ characters, as those should not be present (in the base 64, i.e. outside the header / footer lines obviously). In short, the base 64 (url) decoding fails on multiple levels.
Probably best to use PEM specific encoding / decoding routines. You can find those here if you're using a new runtime, or otherwise you can use the Bouncy Castle libraries.

How to encode to UTF16 Little Endian in Dart?

I am attempting to manipulate some system variables used by a program using Dart. I have encountered the problem of dart's utf package being discontinued, and I have not found any way to encode to UTF 16 Little Endian for a File.write. Is there a library that can do a byte to UTF 16 LE conversion in Dart? I would use UTF anyway, but it is not null safe. I may end up trying to use the utf package source code, but I am checking here to see if there is a native (or pub) implementation I have missed, as I am new to the world of UTF and byte conversions.
My goal:
encodeAsUtf16le(String s);
I do not need to write a BOM.
Dart Strings internally use UTF-16. You can use String.codeUnits to get the UTF-16 code units and then write them in little-endian form:
var s = '\u{1F4A9}';
var codeUnits = s.codeUnits;
var byteData = ByteData(codeUnits.length * 2);
for (var i = 0; i < codeUnits.length; i += 1) {
byteData.setUint16(i * 2, codeUnits[i], Endian.little);
}
var bytes = byteData.buffer.asUint8List();
await File('output').writeAsBytes(bytes);
or assume that you're running on a little-endian system:
var s = '\u{1F4A9}';
var codeUnits = s.codeUnits;
var bytes = Uint16List.fromList(codeUnits).buffer.asUint8List();
await File('output').writeAsBytes(bytes);
Also see https://stackoverflow.com/a/67802971/, which is about encoding UTF-16LE to Strings.
I also feel compelled to advise against writing UTF-16 to disk unless you're forced to by external requirements.

How to set a 24 byte length key to elixir/erlang block_encrypt/4 function using des_ede3 as mode of encryption

Am trying to send data to an external api that expects encrypted data using 3DES encryption but am having issues understanding how to pass my api key as the key field to erlangs des_ede3 cipher.
According to erlangs cipher docs des_ede3 expects 3 keys that are all 8 bytes in length. How can i pass my 24 byte api key as the key to elixir/erlang :cryptoblock_encrypt/4 function
*** how can i pass key to block_encrypt/4 ***
key = "123456789012345678901234"
data = "hello world! The world is yours"
block_size = 8
cipher = :crypto.block_encrypt(:des_ede3, [key, key, key], iv, pad(data, block_size))
How do i pass my 24 byte api key as the key to erlangs block_encrypt/4 in order for me to pass data to the external api.
Thanks
Use binary pattern matching:
<<k1 :: binary-size(8),
k2 :: binary-size(8),
k3 :: binary-size(8)>> = "123456789012345678901234"
#⇒ "123456789012345678901234"
{k1, k2, k3}
#⇒ {"12345678", "90123456", "78901234"}

Convert first two bytes of Lua string (in bigendian format) to unsigned short number

I want to have a lua function that takes a string argument. String has N+2 bytes of data. First two bytes has length in bigendian format, and rest N bytes contain data.
Say data is "abcd" So the string is 0x00 0x04 a b c d
In Lua function this string is an input argument to me.
How can I calculate length optimal way.
So far I have tried below code
function calculate_length(s)
len = string.len(s)
if(len >= 2) then
first_byte = s:byte(1);
second_byte = s:byte(2);
//len = ((first_byte & 0xFF) << 8) or (second_byte & 0xFF)
len = second_byte
else
len = 0
end
return len
end
See the commented line (how I would have done in C).
In Lua how do I achieve the commented line.
The number of data bytes in your string s is #s-2 (assuming even a string with no data has a length of two bytes, each with a value of 0). If you really need to use those header bytes, you could compute:
len = first_byte * 256 + second_byte
When it comes to strings in Lua, a byte is a byte as this excerpt about strings from the Reference Manual makes clear:
The type string represents immutable sequences of bytes. Lua is 8-bit clean: strings can contain any 8-bit value, including embedded zeros ('\0'). Lua is also encoding-agnostic; it makes no assumptions about the contents of a string.
This is important if using the string.* library:
The string library assumes one-byte character encodings.
If the internal representation in Lua of your number is important, the following excerpt from the Lua Reference Manual may be of interest:
The type number uses two internal representations, or two subtypes, one called integer and the other called float. Lua has explicit rules about when each representation is used, but it also converts between them automatically as needed.... Therefore, the programmer may choose to mostly ignore the difference between integers and floats or to assume complete control over the representation of each number. Standard Lua uses 64-bit integers and double-precision (64-bit) floats, but you can also compile Lua so that it uses 32-bit integers and/or single-precision (32-bit) floats.
In other words, the 2 byte "unsigned short" C data type does not exist in Lua. Integers are stored using the "long long" type (8 byte signed).
Lastly, as lhf pointed out in the comments, bitwise operations were added to Lua in version 5.3, and if lhf is the lhf, he should know ;-)

Resources