3

I'm passing an encrypted message between client/server over TCP using AES-GCM-SIV. The received buffer is converted to String and divided into several Vec<&str> using

let v: Vec<&str> = buffer_string.split("?+").collect();

Example of v:

["POST / HTTP/1.1\\r\\n\\", "Uaxh5NUi098q", "178", "[162, 254, 28, 241, ... ]"]

v[3] should be the ciphertext as Vec<u8>. How can the vector be used as Vec<u8>?

iter().map(|c| *c as u8).collect()

would work with chars, not &str.

Here's a complete example on the Playground:

fn main() {
    let buffer_string = r##"POST /chat HTTP/1.1\r\n\?+rRMUG4Lg8Gi6?+178?+[136, 136, 144, 59, 173, 25, 204, 247, 151, 53, 2, 137, 100, 45, 198, 58, 65, 210, 134, 165, 163, 156, 136, 148, 46, 31, 16, 184, 179, 73, 220, 14, 113, 152, 85, 1, 233, 208, 53, 27, 124, 52, 41, 175, 86, 109, 134, 103, 93, 148, 208, 114, 123, 97, 18, 53, 149, 195, 51, 55, 213, 114, 184, 72, 109, 30, 217, 206, 212, 58, 253, 141, 9, 45, 173, 213, 96, 35, 77, 122, 113, 240, 22, 222, 194, 11, 123, 221, 176, 116, 161, 196, 84, 203, 203, 184, 140, 42, 169, 244, 211, 1, 189, 96, 16, 62, 173, 50, 65, 48, 176, 44, 176, 246, 246, 242, 18, 146, 105, 29, 13, 223, 185, 151, 114, 30, 27, 36, 48, 178, 16, 3, 250, 49, 229, 84, 121, 135, 197, 204, 42, 140, 220, 244, 73, 184, 250, 104, 125, 224, 219, 94, 111, 247, 92, 16, 168, 50, 249, 10, 65, 214, 217, 157, 7, 113, 217, 141, 174, 139, 183, 86, 17, 24, 221, 134, 222, 240]"##;

    let v: Vec<&str> = buffer_string.split("?+").collect();
    println!("Vector: v1 {:?}, v2 {:?}, v3: {:?}", v[1], v[2], v[3]);

    //only the v[3] is needed as vec<u8>
    //error with iter and &str
    //let ciphertext_vec: Vec<_> = v[3].iter().map(|c| c.parse::<u8>().unwrap()).collect();

    let ciphertext: Vec<u8> = [
        136, 136, 144, 59, 173, 25, 204, 247, 151, 53, 2, 137, 100, 45, 198, 58, 65, 210, 134, 165,
        163, 156, 136, 148, 46, 31, 16, 184, 179, 73, 220, 14, 113, 152, 85, 1, 233, 208, 53, 27,
        124, 52, 41, 175, 86, 109, 134, 103, 93, 148, 208, 114, 123, 97, 18, 53, 149, 195, 51, 55,
        213, 114, 184, 72, 109, 30, 217, 206, 212, 58, 253, 141, 9, 45, 173, 213, 96, 35, 77, 122,
        113, 240, 22, 222, 194, 11, 123, 221, 176, 116, 161, 196, 84, 203, 203, 184, 140, 42, 169,
        244, 211, 1, 189, 96, 16, 62, 173, 50, 65, 48, 176, 44, 176, 246, 246, 242, 18, 146, 105,
        29, 13, 223, 185, 151, 114, 30, 27, 36, 48, 178, 16, 3, 250, 49, 229, 84, 121, 135, 197,
        204, 42, 140, 220, 244, 73, 184, 250, 104, 125, 224, 219, 94, 111, 247, 92, 16, 168, 50,
        249, 10, 65, 214, 217, 157, 7, 113, 217, 141, 174, 139, 183, 86, 17, 24, 221, 134, 222,
        240,
    ]
    .to_vec();
    let ciphertext2: Vec<u8> = v[3].iter().map(|c| c.parse::<u8>().unwrap()).collect();
    assert_eq!(ciphertext, ciphertext2);

    // ciphertext: Vec<u8> =
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • `&str` has `as_bytes()`, which returns a `&[u8]`, which will probably work just fine. If you truly need a `Vec`, use `.as_bytes().to_vec()`. – user2722968 Oct 01 '19 at 14:21
  • I guess you are searching for this -> [Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=23c6d14c76884326b42361636ed7a3d0) – Ömer Erden Oct 01 '19 at 14:29
  • Unfortunately `.as_bytes().to_vec()` won't work. `"[136, 136, 144,...]" will result in `[91, 49, 51, 54, 44, 32, 49, 51, 54...]` not `[136, 136, 144,...]` – LazyEmpiricist Oct 01 '19 at 14:32
  • It looks like your question might be answered by the answers of [How do I convert a vector of strings to a vector of integers in a functional way?](https://stackoverflow.com/q/34090639/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Oct 01 '19 at 14:38
  • Added an example with assert_eq! I am not able to make the solution in "How do I convert a vector of strings to a vector of integers in a functional way" working in my example, although they are similar. – LazyEmpiricist Oct 01 '19 at 15:03

1 Answers1

3

I believe that does it.

fn main() {
    let s = "[162, 254, 28, 241]";
    let v: Vec<u8> = s
        .trim_start_matches('[')
        .trim_end_matches(']')
        .split(',')
        .map(|c| c.trim().parse::<u8>().unwrap())
        .collect();

    for n in v {
        println!("{}", n);
    }
}

Try it here.

Boiethios
  • 38,438
  • 19
  • 134
  • 183
The Quantum Physicist
  • 24,987
  • 19
  • 103
  • 189
  • input is a number like "162" or "254" not abc, op wants to convert "162":&str to 162u8 – Ömer Erden Oct 01 '19 at 14:22
  • Note that in the example given by the OP, the array is bracketed by `[]`, so he will have to get rid of those – Jmb Oct 01 '19 at 14:39
  • @Jmb I'm hesitating to add a simple `.replace()`... because it's too trivial... – The Quantum Physicist Oct 01 '19 at 14:42
  • Why do you use all those temporary bindings? That feels weird: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=72d5e7c94ffb8b8fd53199c7eec5d7f0 – Boiethios Oct 01 '19 at 15:00
  • @FrenchBoiethios Because I come from a C++ background :D . I fixed my code ;-) – The Quantum Physicist Oct 01 '19 at 15:01
  • Thanks. That did it! [Here is an example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=29fbf8d9b213af4918eed9befb17e4a5) with the solution on the Playground: – LazyEmpiricist Oct 01 '19 at 15:11
  • @TheQuantumPhysicist Well, I wouldn't say that it needed to be "fixed", but that feels more idiomatic IMO. – Boiethios Oct 01 '19 at 15:11
  • 1
    @LazyEmpiricist Just be aware that using `unwrap` in production code is a bad idea. – The Quantum Physicist Oct 01 '19 at 15:16
  • 1
    Using `trim_{start,end}_matches` is more efficient than `replace`. – Shepmaster Oct 01 '19 at 15:18
  • @Shepmaster I was curious about that. It was obvious that looping over the string twice isn't the best way to go. Can you please provide a playground example? – The Quantum Physicist Oct 01 '19 at 15:19
  • https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=805dce9b741c905c1c928ca2d5a19de0. The *loops* are still there, but the *allocation* is removed. To remove the loops, see [Running a number of consecutive replacements on the same string](https://stackoverflow.com/q/27476895/155423) – Shepmaster Oct 01 '19 at 15:19
  • @Shepmaster Thanks. Updated the code. The loop will be there anyway, that's a given. But it'll not loop over the whole string. Just from the beginning to the first instance, and to the last one from behind. That's the optimization I was looking for. – The Quantum Physicist Oct 01 '19 at 15:22
  • If you wanted to remove the multiple loops, you could split on multiple characters (`.split(&[',', '[', ']'][..])`), but only profiling would show which path is faster. – Shepmaster Oct 01 '19 at 15:24
  • @Shepmaster I would use [`try_fold`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3509a042bc3d411e109e2e04aa74b040) instead of silently ignore the errors – Boiethios Oct 01 '19 at 16:02
  • @FrenchBoiethios I'd probably just use `collect` if I cared about the errors. Both versions (ignoring and keeping the errors) are presented in the duplicate question. – Shepmaster Oct 01 '19 at 16:27