How would I convert this Python code into F# "
message = nonce + client_id + api_key
signature = hmac.new(API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper()
My code so far to achieve this:
let message =string(nonce)+ client_id + api_key
let signature = HMACSHA256.Create(API_secret+message)
Simple issue is I cannot find what represents the hexdigest() function in F#.
Also, do I combine the API_Secret with the message as I have done or must they be separated?
I think you need somethink like this:
let hexdigest (bytes : byte[]) =
let sb = System.Text.StringBuilder()
bytes |> Array.iter (fun b -> b.ToString("X2") |> sb.Append |> ignore)
string sb
let signature =
use hmac = new HMACSHA256.Create(API_secret)
hmac.ComputeHash(message)
|> hexdigest
The part with the StringBuilder is what hexdigest does in python (if I get hexdigest right)
Related
On iOS I am generating a pair of private and public key with the following code:
extension Data {
var hexString: String {
return map { String(format: "%02hhx", $0) }.joined()
}
}
let privateKey = P256.Signing.PrivateKey()
let publicKey = privateKey.publicKey
print("private key: " + privateKey.rawRepresentation.hexString)
print("public key: " + "04" + publicKey.rawRepresentation.hexString)
let message = "A message to sign"
let signature = try! privateKey.signature(for: message.data(using: .utf8)!)
print("DER signature: " + signature.derRepresentation.hexString)
print("base64 DER signature: " + signature.derRepresentation.base64EncodedString())
From the code I got:
private key: b02f6fd1c1a9986f0e8cc84cd84a5061e46582e9620981d6dadbc0d503c2be4f
public key: 043fbd15edf44c644e2cdaba55db35170521e5c4bd09156b4930cc5721d64be694191e32f33b7a0b583ca301bd76fb2f93df774eddac72add74ef938d236ad1673
DER signature: 304502200ded05de61c062e9b8c5a3af9b18cdb05bd8d19597494869c150d00f490a3a30022100cf1ca3c6a9c8c1f5fb32e8d101179f64c49f9d69d3043dcd2371fff9a5dd74b3
base64 DER signature: MEUCIA3tBd5hwGLpuMWjr5sYzbBb2NGVl0lIacFQ0A9JCjowAiEAzxyjxqnIwfX7MujRARefZMSfnWnTBD3NI3H/+aXddLM=
I tried to verify the DER signature with the keys through the tool here, which the site determined that the signature is valid.
However, if I try to verify the same result with the following Ruby code using OpenSSL:
group = OpenSSL::PKey::EC::Group.new('prime256v1')
key = OpenSSL::PKey::EC.new(group)
public_key_hex = '043fbd15edf44c644e2cdaba55db35170521e5c4bd09156b4930cc5721d64be694191e32f33b7a0b583ca301bd76fb2f93df774eddac72add74ef938d236ad1673'
public_key_bn = OpenSSL::BN.new(public_key_hex, 16)
public_key = OpenSSL::PKey::EC::Point.new(group, public_key_bn)
key.public_key = public_key
data = 'A message to sign'
signature_base64 = 'MEUCIA3tBd5hwGLpuMWjr5sYzbBb2NGVl0lIacFQ0A9JCjowAiEAzxyjxqnIwfX7MujRARefZMSfnWnTBD3NI3H/+aXddLM='
signature = Base64.decode64(signature_base64)
key.dsa_verify_asn1(data, signature)
The signature is determined to be invalid:
irb(main):074:0> key.dsa_verify_asn1(data, signature)
=> false
I am thinking it is probably due to some format issues of the signature but I don't have any idea or direction to look for. Is this the case? Or did I miss something else?
The Ruby code does not hash the data implicitly, meaning that this must be done explicitly:
...
dataHash = OpenSSL::Digest::SHA256.digest(data)
verified = key.dsa_verify_asn1(dataHash, signature)
print verified # true
With this fix, the verification with the Ruby code is successful.
I would like to use Curl to get the sha256 of a given Nuget package and version. I think this is part of the Nuget API these days, but what URL do I need to hit in order to get the hash?
Thanks for the links, Mauricio Scheffer.
Here is the relevant snippet from Paket:
open System.Net
open System.Xml.Linq
let getDetailsFromNuget name version =
async {
use wc = new WebClient()
let! data =
sprintf "https://www.nuget.org/api/v2/Packages(Id='%s',Version='%s')" name version
|> wc.DownloadStringTaskAsync
|> Async.AwaitTask
let data = XDocument.Parse data
let getAttribute attribute =
let rootNs = XName.Get("entry", "http://www.w3.org/2005/Atom")
let propertiesNs =
XName.Get("properties", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata")
let attributesNs attribute =
XName.Get(attribute, "http://schemas.microsoft.com/ado/2007/08/dataservices")
let properties =
rootNs
|> data.Element
|> fun entry -> entry.Element(propertiesNs)
properties.Element(attributesNs attribute).Value
let packageHash = getAttribute "PackageHash"
let packageHashAlgorithm = getAttribute "PackageHashAlgorithm"
return packageHash, packageHashAlgorithm
}
getDetailsFromNuget "FSharp.Core" "4.3.2"
|> Async.RunSynchronously
|> printfn "%A"
Output:
("CR5/gOr3EXghLOih4N+l8rlM4n5V3Vniv8L8tAeft5+P2QPSpU4CHF0YoTCXUpqfKXRQpvPej70MjHpBfgXJDA==",
"SHA512")
The PackageHashAlgorithm should be "SHA256" or "SHA512".
I have an input string "+20" and I am trying to pass that as query parameter in url.
So I am trying to encode the myInputString by doing
let s1 = myInputString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
But in the debugger, the string s1 still shows as '+20' instead of '%2B20'
Is there something I did wrong?
As already mentioned by matt + is a legal URL character. If you really need to encode it you would need to create your own custom urlQueryAllowed and subtract the plus sign from it:
extension CharacterSet {
static let allowedCharacters = urlQueryAllowed.subtracting(.init(charactersIn: "+"))
}
let myInputString = "+20"
let s1 = myInputString.addingPercentEncoding(withAllowedCharacters: .allowedCharacters) // "%2B20"
I need a simple thing: encode a string in base64. I found an example:
extern crate serialize;
use serialize::base64::{mod, ToBase64};
use serialize::hex::FromHex;
fn main() {
let input = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d";
let result = input.from_hex().unwrap().as_slice().to_base64(base64::STANDARD);
println!("{}", result);
}
Which seams to work but I don't understand why input contains only characters in HEX. Moreover, this Python code produces a different result:
base64.b64encode(input) # =>
'NDkyNzZkMjA2YjY5NmM2YzY5NmU2NzIwNzk2Zjc1NzIyMDYyNzI2MTY5NmUyMDZjNjk2YjY1MjA2MTIwNzA2ZjY5NzM2ZjZlNmY3NTczMjA2ZDc1NzM2ODcyNmY2ZjZk'
So I decided to do the following:
//....
let input = "some string 123";
let result2 = input.unwrap().as_slice().to_base64(base64::STANDARD);
let result3 = input.as_slice().to_base64(base64::STANDARD);
And it didn't compile due to the errors:
error: type `&str` does not implement any method in scope named `unwrap`
test1.rs:9 let result2 = input.unwrap().as_slice().to_base64(base64::STANDARD);
^~~~~~~~
test1.rs:9:34: 9:44 error: multiple applicable methods in scope [E0034]
So how do I encode a simple string in base64?
If you don't have hex input, try this:
let result = input.as_bytes().to_base64(base64::STANDARD);
to_base64 is only defined for a slice of bytes so you have to first call as_bytes on the string:
extern crate serialize;
use serialize::base64::{mod, ToBase64};
fn main() {
let input = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d";
let result = input.as_bytes().to_base64(base64::STANDARD);
println!("{}", result);
}
Input has the type &static str:
let input = "some string 123";
There is no unwrap defined for &'static str:
let result2 = input.unwrap().as_slice().to_base64(base64::STANDARD);
You already have a slice (&str) but you need &[u8]:
let result3 = input.as_slice().to_base64(base64::STANDARD);
That might be the dumbest Rustlang question ever but I promise I tried my best to find the answer in the documentation or any other place on the web.
I can convert a string to a vector of bytes like this:
let bar = bytes!("some string");
Unfortunately I can't do it this way
let foo = "some string";
let bar = bytes!(foo);
Because bytes! expects a string literal.
But then, how do I get my foo converted into a vector of bytes?
(&str).as_bytes gives you a view of a string as a &[u8] byte slice (that can be called on String since that derefs to str, and there's also String.into_bytes will consume a String to give you a Vec<u8>.
Use the .as_bytes version if you don't need ownership of the bytes.
fn main() {
let string = "foo";
println!("{:?}", string.as_bytes()); // prints [102, 111, 111]
}
BTW, The naming conventions for conversion functions are helpful in situations like these, because they allow you to know approximately what name you might be looking for.
To expand the answers above. Here are a few different conversions between types.
&str to &[u8]:
let my_string: &str = "some string";
let my_bytes: &[u8] = my_string.as_bytes();
&str to Vec<u8>:
let my_string: &str = "some string";
let my_bytes: Vec<u8> = my_string.as_bytes().to_vec();
String to &[u8]:
let my_string: String = "some string".to_owned();
let my_bytes: &[u8] = my_string.as_bytes();
String to Vec<u8>:
let my_string: String = "some string".to_owned();
let my_bytes: Vec<u8> = my_string.into_bytes();
Specifying the variable type is optional in all cases. Just added to avoid confusion.
Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5ad228e45a38b4f097bbbba49100ecfc
`let v1: Vec<u8> = string.encode_to_vec();`
`let v2: &[u8] = string.as_bytes();`
two work difference, in some of library use ownership of bytes !! if you use as_bytes() see compiler error: must be static.
for example: tokio_uring::fs::File::write_at()
get a ownership of bytes !!
but if you need borrowing , use as_bytes()