rustcrypto / signatures Goto Github PK
View Code? Open in Web Editor NEWCryptographic signature algorithms: DSA, ECDSA, Ed25519
Cryptographic signature algorithms: DSA, ECDSA, Ed25519
This seems strange since there is the der
feature. Maybe it would make sense to change it to der
? I could submit a PR if this is ok.
Currently the ecdsa
crate's ecdsa::Signer
type only impls RandomizedSigner
and RandomizedDigestSigner
, and uses a k
value derived verbatim from the RNG. This approach is historically fraught with problems and there are better solutions.
Due to an ongoing litany of ECDSA secret key recovery vulnerabilities owing to accidental repetitions of the ECDSA k
(nonce) value for signing multiple messages under the same secret key, deterministic methods of generating k
like RFC 6979 have grown popular. Additionally, a deterministic method would allow us to sign without an RNG, i.e. impl the Signer
and DigestSigner
traits.
Unfortunately, deterministic k
generation makes it easy for an attacker with physical access who can inject faults to potentially induce repeated signatures under the same k
value. An attacker who can inject a fault in the calculation of the ECDSA z
scalar from the message digest some time after k
has been computed (or otherwise inject faults in the subsequent arithmetic on z
) can leverage this to recover the private key.
draft-mattsson-cfrg-det-sigs-with-noise provides a hybrid approach that bolsters an RFC 6979-like construction with additional randomness to ensure k
is still uniformly random per-message in the event of an RNG failure, but also uniquely random every time in the event the RNG is working. Ideally we can change the RandomizedSigner
and RandomizedDigestSigner
traits to use this sort of approach.
Question: is there a reason serde Serialize and Deserialize is not implemented for the ecdsa SigningKey type?
I see implementations for the VerifyingKey and the Signature, but not the SigningKey type.
Is Noah trying to run the example?
fn main() {
use k256::{
ecdsa::{SigningKey, Signature, signature::Signer},
SecretKey,
};
use rand_core::OsRng; // requires 'getrandom' feature
// Signing
let signing_key = SigningKey::random(&mut OsRng); // Serialize with `::to_bytes()`
let message = b"ECDSA proves knowledge of a secret number in the context of a single message";
// Note: the signature type must be annotated or otherwise inferrable as
// `Signer` has many impls of the `Signer` trait (for both regular and
// recoverable signature types).
let signature: Signature = signing_key.sign(message);
// Verification
use k256::{EncodedPoint, ecdsa::{VerifyingKey, signature::Verifier}};
let verify_key = VerifyingKey::from(&signing_key); // Serialize with `::to_encoded_point()`
assert!(verify_key.verify(message, &signature).is_ok());
}
Is Noahs Cargo.toml
[dependencies]
logic = { path="./logic" }
mio = "0.7.11"
ecdsa = { version = "0.10.2", features = ["sign"] }
k256 = { version = "0.7.2", features = ["ecdsa", "sha256"]}
rand_core = "0.6.2"
does throw following error
the trait bound `OsRng: ecdsa::elliptic_curve::rand_core::RngCore` is not satisfied
--> src/main.rs:18:38
|
18 | let signing_key = SigningKey::random(&mut OsRng); // Serialize with `::to_bytes()`
| ^^^^^^^^^^ the trait `ecdsa::elliptic_curve::rand_core::RngCore` is not implemented for `OsRng`
|
::: /home/noone/.cargo/registry/src/github.com-1ecc6299db9ec823/k256-0.7.2/src/ecdsa/sign.rs:37:41
|
37 | pub fn random(rng: impl CryptoRng + RngCore) -> Self {
| ------- required by this bound in `k256::ecdsa::SigningKey::random`
|
= note: required because of the requirements on the impl of `ecdsa::elliptic_curve::rand_core::RngCore` for `&mut OsRng`
error[E0277]: the trait bound `OsRng: ecdsa::elliptic_curve::rand_core::CryptoRng` is not satisfied
--> src/main.rs:18:38
|
18 | let signing_key = SigningKey::random(&mut OsRng); // Serialize with `::to_bytes()`
| ^^^^^^^^^^ the trait `ecdsa::elliptic_curve::rand_core::CryptoRng` is not implemented for `OsRng`
|
::: /home/noone/.cargo/registry/src/github.com-1ecc6299db9ec823/k256-0.7.2/src/ecdsa/sign.rs:37:29
|
37 | pub fn random(rng: impl CryptoRng + RngCore) -> Self {
| --------- required by this bound in `k256::ecdsa::SigningKey::random`
|
= note: required because of the requirements on the impl of `ecdsa::elliptic_curve::rand_core::CryptoRng` for `&mut OsRng`
error: aborting due to 2 previous errors; 4 warnings emitted
Is there any reason SigningKey
does not implement EncodePrivateKey
but only DecodePrivateKey
?
Right now the dsa
crate uses the HmacDrbg
implementation from rfc6979
.
It would be nice to make that a private implementation detail of rfc6979
and switch dsa
to using rfc6979::generate_k_mut
instead, which operates over slices and fills a buffer with k
.
Notably the implementation is dsa
is not constant-time.
When the programm uses in Cargo.toml
ecdsa = "0.10.2"
use ecdsa::{SigningKey, Signature, VerifyingKey};
resolves in
unresolved imports `ecdsa::SigningKey`, `ecdsa::VerifyingKey`
no `SigningKey` in the root
When Add k256 = "0.7.2"
to Cargo.toml
does resolves in build errors
the trait bound `Secp256k1: CheckSignatureBytes` is not satisfied
--> /home/noone/.cargo/registry/src/github.com-1ecc6299db9ec823/k256-0.7.2/src/ecdsa/recoverable.rs:253:26
|
253 | impl From<Signature> for super::Signature {
| ^^^^^^^^^^^^^^^^ the trait `CheckSignatureBytes` is not implemented for `Secp256k1`
|
::: /home/noone/.cargo/registry/src/github.com-1ecc6299db9ec823/ecdsa-0.10.2/src/lib.rs:138:33
|
138 | pub struct Signature<C: Curve + CheckSignatureBytes>
| ------------------- required by this bound in `ecdsa::Signature`
error[E0277]: the trait bound `Secp256k1: CheckSignatureBytes` is not satisfied
--> /home/noone/.cargo/registry/src/github.com-1ecc6299db9ec823/k256-0.7.2/src/ecdsa/recoverable.rs:80:27
|
80 | pub fn new(signature: &super::Signature, recovery_id: Id) -> Result<Self, Error> {
| ^^^^^^^^^^^^^^^^^ the trait `CheckSignatureBytes` is not implemented for `Secp256k1`
|
::: /home/noone/.cargo/registry/src/github.com-1ecc6299db9ec823/ecdsa-0.10.2/src/lib.rs:138:33
|
138 | pub struct Signature<C: Curve + CheckSignatureBytes>
| ------------------- required by this bound in `ecdsa::Signature`
error[E0277]: the trait bound `Secp256k1: CheckSignatureBytes` is not satisfied
--> /home/noone/.cargo/registry/src/github.com-1ecc6299db9ec823/k256-0.7.2/src/ecdsa/recoverable.rs:254:32
|
254 | fn from(sig: Signature) -> Self {
| ^^^^ the trait `CheckSignatureBytes` is not implemented for `Secp256k1`
|
::: /home/noone/.cargo/registry/src/github.com-1ecc6299db9ec823/ecdsa-0.10.2/src/lib.rs:138:33
|
138 | pub struct Signature<C: Curve + CheckSignatureBytes>
| ------------------- required by this bound in `ecdsa::Signature`
error: aborting due to 3 previous errors
Now that the signature
crate is released in some form and being used, the next step I think makes sense is to work on the ed25519
crate (which @newpavlov has already reserved).
I think the best way to keep it simple for an initial release would be to focus exclusively on an ed25519::Signature
type which impls the signature::Signature
trait and can be shared across crates that produce and consume Ed25519 signatures in conjunction with the signature::Signer
and signature::Verifier
traits.
A unified public key type would be nice as well, although the signature
crate presently has no traits relating to public keys, so this seems like a good issue to punt on until the question of the relationship between the signature
crate and public keys is addressed.
An ed25519::Seed
type containing the derivation (via SHA-512) secret for the full keypair might be interesting as well, but also something that seems worthwhile to punt on in the short term.
The main thing needed to implement this is access to R.y
so we can check whether or not it's odd when computing the RecoveryId
.
Related: zkcrypto/group#30
ed25519 v1.5.2 does not build after the release of crate signature 2.0.0, because Cargo.toml is pulling in >1.3.1, which means it's pulling in 2.0.0 now and that breaks the build
The num-bigint
(-dig) crate(s) implement operations in a non-constant-time manner. Notably they include a normalize
function which strips trailing zeros, which is called all over the place.
The crypto-bigint
crate has been written from the ground-up paying attention to constant-time, and the latest crypto-bigint
prereleases support a BoxedUint
which is suitable for use with dsa
:
https://docs.rs/crypto-bigint/0.6.0-pre.11/crypto_bigint/struct.BoxedUint.html
Additionally, the latest prerelease of the crypto-primes
crate support generic operation over Uint
and BoxedUint
:
https://docs.rs/crypto-primes/0.6.0-pre.0/crypto_primes/fn.generate_prime_with_rng.html
Currently it returns Option<Self>
which:
s
is public, but is surprising to anyone analyzing the side channels of signing)Proposed changes:
Self
;is_low_s() -> Choice
method to provide a better encapsulation of the check (to be used in verification);NormalizedSignature
type, and have normalize_s() -> NormalizedSignature
As you wrote in #32 the main motivation for releasing signature v1.0
is to enable use of it for dalek crates. But IIUC dalek developers haven't confirmed that they intend to depend on signature
and I though a better approach will be to use ed25519
crate as a wrapper around ed25519-dalek
to implement signature
traits. This would allow dalek
developers to be independent from our work on signature
API and we will have more freedom to experiment with it.
As for transferring signature
to the traits repo, we should certainly do it, but I think it will be better to postpone it until beginning of the next year (hopefully I will have more time to work on this project at that time).
Currently there's no way to catch the error when deserializing an invalid signature, because it uses Signature::from
that panics:
Lines 544 to 546 in e478469
As of #78, the encoding for formats that "serialize byte slices more compactly or more efficiently than other types of slices" (to quote serde's docs) may be worse.
For example, using Message Pack (via rmp_serde
), the tuple-based approach leads to encoding as an array where each element is individually encoded, hence each element needs an additional type tag byte (though Message Pack encodes integers <128 with a single byte, so on average only ~50% of values get inflated this way).
Although my specific use-case is with Message Pack, I assume this issue would affect other formats with specific byte array encodings, though I don't know how common that is (as serde has first-class support in their data model, I'd guess it's not too uncommon?).
It's certainly possible to work around this downstream using #[serde(with = "...")]
et-al, but I wanted to check whether this was considered when implementing #78, and considered desired behaviour, or if the bincode optimisation could be dropped for broader compatibility.
Edit: I guess this is basically a choice between known-size or known-type optimisations. A known-size byte array could benefit from both, but serde's data model doesn't support it.
Currently SigningKey
is not Clone, which is needed in many applications and I see no reason why it should not be Clone.
P-521 is of course an unusual edge case in that it has an odd(ly shaped) field size and one that exceeds the size of e.g. SHA-512.
#775 unsuccessfully attempts to add the test vector.
We're getting close to ready to cut a final release of Edit: released!signature
v2.0.0: RustCrypto/traits#1171
This is a tracking and discussion issue for any final changes before releasing the following:
When I debug-format the Signature type, I get some very long output (see below). But it would be much easier to read and copy shorter hex-encoded output.
Expected output:
sig: ed25519::Signature {
R: "e8...",
s: "77...",
}
Actual output:
sig: ed25519::Signature {
R: [
232,
35,
39,
173,
39,
51,
101,
13,
82,
4,
201,
65,
153,
155,
75,
114,
8,
44,
128,
70,
20,
142,
169,
129,
27,
35,
129,
240,
229,
20,
112,
240,
],
s: [
119,
225,
75,
170,
146,
238,
92,
78,
105,
184,
143,
18,
153,
212,
246,
171,
34,
106,
132,
183,
50,
226,
59,
202,
111,
193,
180,
80,
34,
219,
107,
243,
],
},
Did try the following
let signing_key = SigningKey::random(&mut OsRng); // Serialize with `::to_bytes()`
println!("{:?}", SecretKey::from_bytes(signing_key.to_bytes()).into_iter().collect::<Vec<_>>());
does give
[SecretKey<Secp256k1>{ ... }]
How to get secret key and private key from signing key?
Not sure if this is a question for signatures or elliptic-curves but I'm trying to generate a JWK token from a SigningKey<NistP256>
Unfortunately it needs access to the "x" (X Coordinate)
and "y" (Y Coordinate)
Parameters from the AffinePoint
. Is this even possible currently?
It seems I have broken the CI because I didn't know that you can only use working-directory
with run
and not with uses
. The reason I didn't notice was because for some reason these jobs didn't show up in the PR.
What
Using Signature::try_from
can panic in a specific case, due to the interactions between rust's auto-implementations and user oversight.
Expected Behavior
try_from
should either return an Ok
or Error
Actual Behavior
Given the following code, if the user makes the mistake of passing the bytes as value [u8; 64]
instead of a reference &[u8]
, try_from
will accept that input and potentially panic at runtime for invalid input.
let sig = [255u8; 64];
if let Ok(s) = Signature::try_from(sig) { // should've been `sig.as_ref()`
...
}
thread 'main' panicked at 'invalid signature: signature::Error { source: None }', /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/ed25519-1.5.2/src/lib.rs:331:38
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Explanation
This is because the From<[u8; 64]>
albeit deprecated, is still implemented. Even though TryFrom<&[u8]>
is the only impl available, Rust auto-impls TryFrom<[u8; 64]>
via From<u8; 64>
.
This is quite significant as a single error can give the user the impression that they'll get a Result
, whereas the codepath can potentially panic instead.
Removing From<[u8; 64]>
implementation should fix this behavior.
I'm trying to convert signature to low S, but got compilation error.
Dependencies used:
ecdsa = "0.12"
elliptic-curve = "0.10"
p256 = "0.9"
Error:
let signature = Signature::<p256::NistP256>::from_der(&data)?;
signature.normalize_s()?;
^^^^^^^^^^^ the trait `NormalizeLow` is not implemented for `Scalar`
How to fix it? What exact type need to implement trait NormalizeLow?
Hi, I'm following up on a build error that was reported to us:
warning[yanked]: detected yanked crate
┌─ /github/workspace/Cargo.lock:123:1
│
123 │ ed25519 1.5.2 registry+https://github.com/rust-lang/crates.io-index
│ ------------------------------------------------------------------- yanked version
│
= ed25519 v1.5.2
├── ed25519-dalek v1.0.1
https://github.com/mobilecoinofficial/deqs/actions/runs/4348477341/jobs/7597062019
We get this error because we have a deny.toml
file which detects yanked crates and reports them to us so that we can learn about security issues immediately and fix them.
It looks to me that the only difference between 1.5.2 and 1.5.3 is this change: 35ee637
As politely as I can, I want to suggest that this might not have been an inappropriate use of yanking. Yanking the old version just because you published a new one is harmful to downstream users.
This is not a security issue, there is nothing that urgently requires us to update from 1.5.2 to 1.5.3. To accomplish that we would have to coordinate with dalek maintainers as well, or fork dalek, which is a lot of work.
Cargo will automatically cause any new users of your crate to select 1.5.3 and not 1.5.2 due to cargo's interpretation of semver anyways.
Use of yanking when there is not a security issue will force us to disable tools that help us detect yanked crates and find actual security problems, or force us to vendor the software to ourselves outside of crates.io to avoid build breakage when checking out old commits, for example, when using git bisect to find and fix bugs.
The r
scalar component of an ECDSA signature is computed by lifting the affine x-coordinate of the curve point 𝑹 = 𝑘×𝑮 into an integer and reducing it modulo the curve's order into an element of the scalar field.
Though occurring infrequently (sometimes with a vanishingly small probability), this condition results in RecoveryId
values of 2 or 3.
Presently only RecoveryId
values of 0 or 1 are supported, and the others will result in an error when recovering the verifying key.
The test suite currently only tests against a few RFC test vectors, importing the Wycheproof vectors would be nice to improve the confidence in the correctness of the implementation.
In RSA, there are multiple schemes to sign/verify, mainly PKCS1 v1.5 and PSS (although others exists). I was looking at how to integrate signature
into the RSA crate, and was a bit confused at the lack of a Padding argument or type in Signer
/Verifier
. Is the idea to implement Verifier
on a type that is already aware of the padding scheme?
Hi,
I'm in a case where I need to verify a signature done on a whole &[u8] rather than a digest and I see that the relevant method is in the Verifier
trait but it is not implemented anywhere in the dsa
crate.
Is that an oversight or it is something just waiting for a contribution? Or am I missing something?
Regards,
I believe the current ecdsa code uses from_repr
and to_repr
when generating a k
value in ways which are only fully compliant with RFC6979 if the internal representation is big endian. The docs for these functions claim that the endianness of the internal representation is not defined at the trait level.
I'm assuming current curves choose a big endian representation, but it would be better to use an API which provides defined endianness.
The reason I'm making an issue out of this is because it seems sloppy to use APIs with undefined endianness and since I'm working on DSA related code I'd like to understand the situation.
The code in question:
signatures/ecdsa/src/rfc6979.rs
Lines 31 to 42 in bfd60ba
Hello! 👋
what would be required for SHA3 hashing support for hazmat::DigestPrimitive?
I'm signing data using Google Cloud's KMS like this. I'm using the EC_SIGN_P256_SHA256 algorithm described here to sign JWTs.
I've seen the signatures vary in size from 70 to 72 bytes.
When I try to verify a JWT with this code:
use jwt_simple::prelude::*;
let key = ES256PublicKey::from_pem(SIGN_JWT_KEY).unwrap();
let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJodHRwczovL3BkZnNuYWtlLmFwcCIsImF1ZCI6InBkZnNuYWtlLWNsaS1iZXRhIiwic3ViIjoiamVmZkByZW5uaWVnbGVuLmNvbSIsIm5iZiI6MTY1Mzg1NzM3OSwiaWF0IjoxNjUzOTQzNzc5LCJleHAiOjE2NjQ1ODI0MDB9.MEYCIQCOuDGCoSEsezIWhceth1v7tjkoWM3jG6xRErdZYfPc8QIhAKHQKO9XACs-M-JHU-jhHmBMhBCiNB6RVrwLuaZsdySh";
let options = VerificationOptions::default();
let claims = key.verify_token::<NoCustomClaims>(&token, Some(options)).unwrap();
println!("{:?}", claims);
I get the error:
thread 'tests::test_jwt' panicked at 'called `Result::unwrap()` on an `Err` value: Signature tag didn't verify'
Stepping through the code, I see that this line returns an error:
if bytes.len() != C::UInt::BYTE_SIZE * 2 {
return Err(Error::new());
}
From the comments, it looks like this library expects signatures to always have a fixed size, perhaps 64 bytes? That disagrees with the ecdsa signatures generated by Google Cloud KMS, which I've seen vary in size between 70 and 72 bytes.
This discussion on stack overflow also arrives at the conclusion that the maximum size for an ecdsa signature is 72 bytes.
Hello 👋
I'm Emil, Security Engineer at Wire (github.com/wireapp) an E2EE secure messenger. We recently conducted a security audit of our core-crypto library which implements the MLS standard and the external researchers found an issue in the P256 + RFC6979 implementation leading to non conforming signatures.
private key = 1888cb732fea4353451b856e4f2c0715163bcf4bb7788ab44f70ef9ff9727167
message = 049a27b521c74e81
Expected signature:
9ac51396b0c8d0a5a082b5d88b45760504c1e7c8ba1a49e8b40f4098ac74c757563050ecbfc45165503f9ef57b3039baae0000d6eebcecd922bb280b35d2db79
Actual signature using p256 version 0.13.2
5dcd6baac9e02e2351763333d40d73157d4fee343954c7a380c7fb688f9ef9609f473dcdbc0fbc2bcf020ac3cf5eeed9d88634c0014419a0bdc4c0f88341ca57
This seems to have been fixed in p256 0.14.0-pre.0
which produces the correct signature.
Since this doesn't have security implications for Wire but might have implications for other users, I'd suggest investigating the implementation.
Cheers & thank you for your work <3
PS: A more detailed writeup is available to @tarcieri
I'm not super familiar with the details of ECDSA, but for my workload this verify_prehash
check doubles the runtime. Is there any situation where this check will actually fail?
Hello,
I have been using this library to generate Secp256k1 signatures.
When I started writing a JavaScript client to the system I was building, I noticed that the signatures generated in this library and the ones in JS are different.
I then tried comparing this implementation with a different Rust implementation, and the signatures are also off (the other lib agrees with JS).
I wrote a test demonstrating this: https://github.com/TheReturnOfJan/rust-crypto-bug/blob/master/tests/test.rs
Could this be an issue with how the field elements are serialized? Or is it possible that there is a bug in the ecdsa implementation?
Ok so I tried to recover the sig generated by the other lib with this lib, and I get the same results. I guess the different sigs have something to do with how the k parameter is generated? Anyway, apologies for spamming the issues with this, will close this.
Currently rfc6979
bundles a tiny, slow, byte-oriented bignum library: https://github.com/RustCrypto/signatures/blob/master/rfc6979/src/ct.rs
Several of the interfaces described in RFC6979 describe an "int" type, perhaps most notably the bits2int
function (which is partially implemented in the ecdsa
crate in the form of bits2field
). However all of the APIs in rfc6979
are byte/octet-oriented, which can make things a bit awkward.
With crypto-bigint
now supporting a heap-allocated BoxedUint
and plans to migrate the dsa
crate to that (#779), as well as having traits for abstracting over stack-vs-heap allocated big integers in crypto-bigint
like Integer
and Monty
, it becomes possible to make rfc6979
closer to 1:1 with the APIs described in the RFC while being able to support both the dsa
and ecdsa
use cases.
Isn't the signature
version requirement of ecdsa
too lax to comply with semver?
The signature
crate reserves itself the right to bump the MSRV and the digest
and rand
dependencies in a minor version bump.
Currently ecdsa
has the version requirement of ^1.5
which includes 1.6
, 1.7
, etc. which could have breaking changes regarding either the MSRV or the above mentioned dependencies.
I'm a beginner & contribute around GitHub in small portions, I create algorithms, like ciphers in rust I tried a few in my repo.
I was hoping to contribute the RSA signature, as I noticed we don't have one, but I'm not sure if someone is already working on it, if yes, I can jump in to learn & start my journey here to contribute.
Thanks!
Is anyway to store signing_keys in a file or in a keyvalue db?
Is possible to use a different random in SigningKey::random()
?
We could potentially adapt the ECDSA public key recovery algorithm implemented in k256
into a generic implementation which works with any elliptic curve.
It could use ecdsa::RecoveryId
as an input parameter, leaving exactly how to encode that as an exercise to the user.
I would probably suggest implementing the algorithm as something like VerifyingKey::recover(msg, sig, rec_id)
.
Presently the signing and verification key types are named SigningKey
and VerifyKey
. These are a bit inconsistent with each other grammatically. Per a Twitter straw poll, in particular people seem to dislike the current names.
Some potential alternatives:
ecdsa::{SignKey, VerifyKey}
ecdsa::{SigningKey, VerifyingKey}
ecdsa::key::{Sign, Verify}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.