public static ArrayLease <byte> DecryptHexToBytes(string ciphertext, ArraySegment <byte> key, out int count) { // Throw if the string isn't divisible by 2, since bytes are 2 hex digits if ((ciphertext.Length & 1) != 0) // ciphertext.Length % 2 != 0 { // TODO: Strings.resx if it's worth it (see notes above) throw new ArgumentException( message: "The ciphertext needs to be hex-encoded and have a length divisible by 2.", paramName: nameof(ciphertext)); } int bufferLength = ciphertext.Length / 2; var rented = ArrayPool <byte> .Shared.Rent(bufferLength); try { Debug.Assert(bufferLength <= rented.Length); // Do the translation via Hexadecimal.ToByte int i = 0, j = 0; while (i < bufferLength) { rented[i] = Hexadecimal.ToByte(ciphertext[j], ciphertext[j + 1]); i += 1; j += 2; } Debug.Assert(i == bufferLength && j == i * 2); // Now call DecryptBytes with the key/encrypted buffer var encryptedBytes = new ArraySegment <byte>(rented, 0, bufferLength); return(DecryptBytes(encryptedBytes, key, out count)); } finally { ArrayPool <byte> .Shared.Return(rented); } }