Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace rust-crypto crate with RustCrypto crates #239

Merged
merged 10 commits into from
Mar 20, 2019

Conversation

newpavlov
Copy link
Contributor

As was discussed in the #128. Currently this PR lacks only AES-CTR in audio/src/decrypt.rs and connect/src/discovery.rs, which will require some work on RustCrypto side.

@newpavlov newpavlov changed the title WIP: Replace rust-crypto crate with RustCrypto crates Replace rust-crypto crate with RustCrypto crates Jul 30, 2018
@newpavlov
Copy link
Contributor Author

Note that aes-ctr requires Rust 1.27 (as it depends on stabilized target features). To have the best performance on modern x86-64 CPUs you'll need to enable aes and ssse3 target features.

@ashthespy
Copy link
Member

Tested on armv7 and all seems to work well here.
Don't know enough to check performance vs the earlier implementation!

@ashthespy
Copy link
Member

@newpavlov 1f1cd11 seems to be giving me Bus errors on aarch64 (running armv7hf 32bit binary):

Program received signal SIGBUS, Bus error.
[Switching to Thread 0xf69ff2a0 (LWP 16863)]
0xaab85efc in _$LT$ctr..Ctr128$LT$C$GT$$u20$as$u20$stream_cipher..NewFixStreamCipher$GT$::new::h428d9f3e664339b6 ()
(gdb) backtrace
#0  0xaab85efc in _$LT$ctr..Ctr128$LT$C$GT$$u20$as$u20$stream_cipher..NewFixStreamCipher$GT$::new::h428d9f3e664339b6 ()
#1  0xaab7f664 in librespot_playback::player::PlayerInternal::run::h11714ef38d488ae5 ()
Cannot access memory at address 0x0
#2  0xf69fcee0 in ?? ()
Cannot access memory at address 0x0
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)

Any ideas how to debug/isoloate this further?

@newpavlov
Copy link
Contributor Author

newpavlov commented Oct 12, 2018

Hm, I think problem manifests itself in this line, not sure why it happens though. Are you sure that nonce pointer is not null?

UPD: Hm, looking at the code it looks like pointer can not be null...

@ashthespy
Copy link
Member

ashthespy commented Oct 12, 2018

Hm, I think problem manifests itself in this line, not sure why it happens though. Are you sure that nonce pointer is not null?

I am a gdb novice - so my knowledge stops at :={
How exactly can I check?

(gdb) frame
#0  0xaab85efc in _$LT$ctr..Ctr128$LT$C$GT$$u20$as$u20$stream_cipher..NewFixStreamCipher$GT$::new::h428d9f3e664339b6 ()
(gdb) info f
Stack level 0, frame at 0xf65f7b40:
 pc = 0xaab85efc
    in _$LT$ctr..Ctr128$LT$C$GT$$u20$as$u20$stream_cipher..NewFixStreamCipher$GT$::new::h428d9f3e664339b6; saved pc = 0xaab7f664
 called by frame at 0xf65fce70
 Arglist at 0xf65f60b0, args:
 Locals at 0xf65f60b0, Previous frame's sp is 0xf65f7b40
 Saved registers:
  r4 at 0xf65f7b1c, r5 at 0xf65f7b20, r6 at 0xf65f7b24, r7 at 0xf65f7b28, r8 at 0xf65f7b2c,
  r9 at 0xf65f7b30, r10 at 0xf65f7b34, r11 at 0xf65f7b38, lr at 0xf65f7b3c
(gdb)

and

(gdb) x/3ug 0xaab85efc
0xaab85efc <_ZN74_$LT$ctr..Ctr128$LT$C$GT$$u20$as$u20$stream_cipher..NewFixStreamCipher$GT$3new17h428d9f3e664339b6E+20>:       16325108307302940720    16540877113332465672
0xaab85f0c <_ZN74_$LT$ctr..Ctr128$LT$C$GT$$u20$as$u20$stream_cipher..NewFixStreamCipher$GT$3new17h428d9f3e664339b6E+36>:       16540877096152596492

@ashthespy
Copy link
Member

ashthespy commented Oct 12, 2018

I could not reproduce it with the usage example over at docs. But if you have a better test case to isolate the issue, willing to test!

@newpavlov
Copy link
Contributor Author

Please try to execute aes-ctr tests on your platform. Meanwhile I will write a small replacement for this line, which you will be able to test via [patch].

@newpavlov
Copy link
Contributor Author

Try to do the following:

  1. Clone ctr crate from the repo.
  2. Replace line 105 with this code:
let nonce = [
    ((nonce[0] as u64) << 8*7) + ((nonce[1] as u64) << 8*6) +
    ((nonce[2] as u64) << 8*5) + ((nonce[3] as u64) << 8*4) +
    ((nonce[4] as u64) << 8*3) + ((nonce[5] as u64) << 8*2) +
    ((nonce[6] as u64) << 8*1) + ((nonce[7] as u64) << 8*0),
    ((nonce[8] as u64) << 8*7) + ((nonce[9] as u64) << 8*6) +
    ((nonce[10] as u64) << 8*5) + ((nonce[11] as u64) << 8*4) +
    ((nonce[12] as u64) << 8*3) + ((nonce[13] as u64) << 8*2) +
    ((nonce[14] as u64) << 8*1) + ((nonce[15] as u64) << 8*0),
];
  1. Add [patch] section to librespot's Cargo.toml in which replace ctr crate with your modified copy:
[patch.crates.io]
ctr = { path = 'path/to/modified/ctr' }
  1. Test resulted binary.

@ashthespy
Copy link
Member

ashthespy commented Oct 12, 2018

I don't know how to run cargo test when cross compiling. I tried taking the resulting binary from cargo --test --release --target arm-unknown-linux-gnueabihf and it didn't do anything (Ran test 0 of 0)

But this gets interesting - I just added a simple debug to try and recreate a simpler minimal example,

println!("key: {:?}", key.0);
let cipher = Aes128Ctr::new(
            &GenericArray::from_slice(&key.0),
            &GenericArray::from_slice(&AUDIO_AESIV),
        );

and it doesn't have any bus errors now?

Either way - building with the patch now
EDIT: [patch.crates.io] --> [patch.crates-io]

@ashthespy
Copy link
Member

Your patch works! I couldn't get the [patch] syntax working - I didn't seem to be able to get it to patch dependencies (ctr) of aes-ctr but that is a different matter! :)
Thanks for the quick response!

@newpavlov
Copy link
Contributor Author

Hm, now we need to find if I've maid a mistake and the line introduces UB, or is it Rust miscompialtion. One possible explanation is alignment issues, not sure how to check it though. :/ I will try to ask around.

@ashthespy
Copy link
Member

Hm, now we need to find if I've maid a mistake and the line introduces UB, or is it Rust miscompialtion. One possible explanation is alignment issues, not sure how to check it though. :/ I will try to ask around.

  1. Naive question - was it just a coincidence that this error didn't manifest when I added the print?

  2. If you have some tests that I can cross compile with my current toolchain, will be happy to test for you!

@newpavlov
Copy link
Contributor Author

Naive question - was it just a coincidence that this error didn't manifest when I added the print?

UB and miscompilation bugs are quite fragile, and can result in big behaviour changes on small code edits.

If you have some tests that I can cross compile with my current toolchain, will be happy to test for you!

I can translate tests to a stand-alone app, but I probably will do it tomorrow.

BTW have you updated Rust to 1.29.2? I doubt that this miscomiplation bug causes this situation, but it's worth to check.

@ashthespy
Copy link
Member

ashthespy commented Oct 13, 2018

Fair enough with the undefined behaviour.
I just checked, I was building both with 1.29.1 and 1.29.2 - both of them had the error.

@newpavlov
Copy link
Contributor Author

Try to test the following snippet:

extern crate aes_ctr;

use aes_ctr::Aes128Ctr;
use aes_ctr::stream_cipher::{NewFixStreamCipher, StreamCipherCore};
use aes_ctr::stream_cipher::generic_array::GenericArray;

const AUDIO_AESIV: [u8; 16] = [
    0x72, 0xe0, 0x67, 0xfb, 0xdd, 0xcb, 0xcf, 0x77,
    0xeb, 0xe8, 0xbc, 0x64, 0x3f, 0x63, 0x0d, 0x93,
];

#[inline(never)]
fn new_cipher(key: &[u8]) -> Aes128Ctr {
    Aes128Ctr::new(
        GenericArray::from_slice(key),
        GenericArray::from_slice(&AUDIO_AESIV),
    )
}

#[inline(never)]
fn encrypt(cipher: &mut Aes128Ctr) -> [u8; 10] {
    let mut data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    cipher.apply_keystream(&mut data);
    data
}

fn main() {
    let mut cipher = new_cipher(b"0123456789abcdef");
    let data = encrypt(&mut cipher);
    println!("{:?}", data);
}

@newpavlov
Copy link
Contributor Author

Any news on this?

I've updated Cargo.lock after merge, as it was the easiest way to merge.

@sashahilton00
Copy link
Member

Sorry, this PR kind of got lost to the winds. If you wouldn't mind rebasing this, we'll review it and hopefully get it merged.

@newpavlov
Copy link
Contributor Author

No problem! I've rebased PR and additionally fixed one security related mistake.

assert_eq!(data % block_size, 0);
for chunk in data.chunks_mut(block_size) {
cipher.decode(GenericArray::from_slice_mut(chunk));
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about this part. Can it be assumed that data here is always multiple of 16?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it doesn't look like it. I just checked with my stored blob, where the hex blob was 286 characters

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, this is quite strange. If ECB (or CBC) mode was used encrypted message length should be a multiple of block size. Do you have any test vectors for those encrypted blocks or implementations which can be used as a reference?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will have to check later. I don't believe so, I believe we just store the bllob as we receive it, no telling what parameters are used in it's creation.

@sashahilton00
Copy link
Member

Thanks, will test this and review tomorrow hopefully. Also, could you squash the recent commits by any chance?

@sashahilton00
Copy link
Member

This seems to work fine. Once the last few commits are squashed will merge.

@newpavlov
Copy link
Contributor Author

newpavlov commented Mar 16, 2019

Done! Don't forget about checking decryption in Credentials::with_blob and ideally it would be nice to add some tests for it.

@sashahilton00
Copy link
Member

I authed using zeroconf, then restarted with cached credentials and it worked fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants