# ECDSA (Elliptic Curve Digital Signature Algorithm)

### 🎯 Descrição Geral

**ECDSA (Elliptic Curve Digital Signature Algorithm)** é a versão do DSA (Digital Signature Algorithm) sobre **curvas elípticas**. Ele permite que uma entidade assine digitalmente uma mensagem usando sua **chave privada**, e qualquer outra entidade pode verificar a assinatura usando a **chave pública** correspondente.

```
┌─────────────────────────────────────────────────────────────┐
│                        ASSINATURA                            │
│                                                              │
│   Mensagem + Chave Privada ──► ECDSA ──► Assinatura (r, s)  │
│                                                              │
│                        VERIFICAÇÃO                           │
│                                                              │
│   Mensagem + Chave Pública + Assinatura ──► Válido/Inválido │
└─────────────────────────────────────────────────────────────┘
```

#### Analogia

> *"ECDSA é como um carimbo digital único. Só você tem o carimbo (chave privada), mas qualquer um pode verificar se o carimbo é seu (chave pública)."*

***

### ⚙️ Como Funciona o ECDSA

#### Parâmetros da Curva

```
Curva: y² = x³ + ax + b (mod p)

Parâmetros públicos:
- p: número primo (corpo finito)
- a, b: coeficientes da curva
- G: ponto base (gerador)
- n: ordem de G (número de pontos no subgrupo)
- h: cofator (n × h = número total de pontos)
```

#### Geração de Chaves

```python
# 1. Escolher chave privada (número aleatório entre 1 e n-1)
d = random.randint(1, n-1)

# 2. Calcular chave pública (ponto na curva)
Q = d × G  # multiplicação escalar

# Saída:
# Chave Privada: d
# Chave Pública: Q (x, y)
```

#### Algoritmo de Assinatura

```python
def ecdsa_sign(mensagem, chave_privada_d, curva):
    # 1. Calcular hash da mensagem
    h = SHA256(mensagem)
    z = int(h, 16) % n  # parte do hash (bits mais à esquerda)
    
    # 2. Escolher k aleatório (NÃO REUTILIZAR!)
    k = random.randint(1, n-1)
    
    # 3. Calcular ponto (x1, y1) = k × G
    x1, y1 = k * G
    
    # 4. Calcular r = x1 mod n
    r = x1 % n
    if r == 0:
        # Escolher outro k
        return ecdsa_sign(mensagem, chave_privada_d, curva)
    
    # 5. Calcular s = k⁻¹ × (z + r × d) mod n
    s = (mod_inverse(k, n) * (z + r * d)) % n
    if s == 0:
        # Escolher outro k
        return ecdsa_sign(mensagem, chave_privada_d, curva)
    
    # 6. Assinatura é o par (r, s)
    return (r, s)
```

#### Algoritmo de Verificação

```python
def ecdsa_verify(mensagem, assinatura, chave_publica_Q, curva):
    r, s = assinatura
    
    # 1. Validar r e s (1 <= r,s <= n-1)
    if not (1 <= r <= n-1 and 1 <= s <= n-1):
        return False
    
    # 2. Calcular hash da mensagem
    h = SHA256(mensagem)
    z = int(h, 16) % n
    
    # 3. Calcular w = s⁻¹ mod n
    w = mod_inverse(s, n)
    
    # 4. Calcular u1 = z × w mod n
    u1 = (z * w) % n
    
    # 5. Calcular u2 = r × w mod n
    u2 = (r * w) % n
    
    # 6. Calcular ponto P = u1 × G + u2 × Q
    P = (u1 * G) + (u2 * Q)
    
    # 7. Verificar se P.x mod n == r
    return (P.x % n) == r
```

***

### 🔢 Exemplo Numérico Simplificado

#### Parâmetros (curva pequena para exemplo)

```
Curva: y² = x³ + 2x + 3 (mod 17)
G = (5, 1)
n = 19 (ordem de G)
```

#### Geração de Chaves

```
Chave privada d = 10
Chave pública Q = 10 × G = (9, 2)
```

#### Assinatura (mensagem hash z = 7)

```
1. k aleatório = 5
2. k × G = (14, 9) → r = 14
3. s = 5⁻¹ × (7 + 10 × 14) mod 19
   5⁻¹ mod 19 = 4 (pois 5×4=20≡1 mod19)
   s = 4 × (7 + 140) = 4 × 147 = 588 mod 19 = 18
4. Assinatura = (14, 18)
```

#### Verificação

```
1. w = 18⁻¹ mod 19 = 18 (pois 18×18=324≡1)
2. u1 = 7 × 18 mod 19 = 126 mod 19 = 12
3. u2 = 14 × 18 mod 19 = 252 mod 19 = 5
4. P = 12×G + 5×Q
   12×G = (2, 11)
   5×Q = (3, 5)
   P = (2,11) + (3,5) = (14, 9)
5. P.x = 14 = r → Assinatura VÁLIDA ✅
```

***

### 📊 Curvas ECDSA Padrão (NIST)

| Curva                 | Tamanho  | Bits de Segurança | Uso              | Status        |
| --------------------- | -------- | ----------------- | ---------------- | ------------- |
| **P-192** (secp192r1) | 192 bits | 96 bits           | Legado           | ❌ Obsoleta    |
| **P-224** (secp224r1) | 224 bits | 112 bits          | Governo US       | ⚠️ Permitida  |
| **P-256** (secp256r1) | 256 bits | 128 bits          | Padrão           | ✅ Recomendada |
| **P-384** (secp384r1) | 384 bits | 192 bits          | Alto nível       | ✅ Recomendada |
| **P-521** (secp521r1) | 521 bits | 256 bits          | Máxima segurança | ✅ Recomendada |

#### Curvas Alternativas (Não NIST)

| Curva               | Criador   | Tamanho  | Vantagem                             |
| ------------------- | --------- | -------- | ------------------------------------ |
| **secp256k1**       | Certicom  | 256 bits | Bitcoin, Ethereum                    |
| **brainpoolP256r1** | Brainpool | 256 bits | Gerada randomicamente (sem backdoor) |
| **Ed25519**         | Bernstein | 256 bits | Mais rápida, EdDSA (não ECDSA)       |

***

### 💻 Exemplos Práticos

#### Exemplo 1 – Gerar Chaves ECDSA (OpenSSL)

```bash
# Gerar chave privada ECDSA (curva P-256)
openssl ecparam -name prime256v1 -genkey -out ecdsa_private.pem

# Extrair chave pública
openssl ec -in ecdsa_private.pem -pubout -out ecdsa_public.pem

# Verificar chaves
openssl ec -in ecdsa_private.pem -text -noout
openssl ec -pubin -in ecdsa_public.pem -text -noout
```

#### Exemplo 2 – Assinar e Verificar (OpenSSL)

```bash
# Criar arquivo
echo "Documento importante" > documento.txt

# Assinar com SHA-256
openssl dgst -sha256 -sign ecdsa_private.pem -out signature.bin documento.txt

# Verificar assinatura
openssl dgst -sha256 -verify ecdsa_public.pem -signature signature.bin documento.txt

# Output: Verified OK
```

#### Exemplo 3 – ECDSA em Python (cryptography)

```python
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat, PrivateFormat, NoEncryption

# Gerar chave privada (P-256)
private_key = ec.generate_private_key(ec.SECP256R1())
public_key = private_key.public_key()

# Assinar mensagem
message = b"Mensagem super secreta"
signature = private_key.sign(
    message,
    ec.ECDSA(hashes.SHA256())
)

print(f"Assinatura (hex): {signature.hex()}")

# Verificar assinatura
try:
    public_key.verify(signature, message, ec.ECDSA(hashes.SHA256()))
    print("✅ Assinatura VÁLIDA!")
except:
    print("❌ Assinatura INVÁLIDA!")

# Salvar chaves
with open("ecdsa_private.pem", "wb") as f:
    f.write(private_key.private_bytes(
        encoding=Encoding.PEM,
        format=PrivateFormat.PKCS8,
        encryption_algorithm=NoEncryption()
    ))

with open("ecdsa_public.pem", "wb") as f:
    f.write(public_key.public_bytes(
        encoding=Encoding.PEM,
        format=PublicFormat.SubjectPublicKeyInfo
    ))
```

#### Exemplo 4 – ECDSA com secp256k1 (Bitcoin)

```python
# pip install coincurve
import coincurve
import hashlib

# Gerar chave
private_key = coincurve.PrivateKey()
public_key = private_key.public_key

print(f"Chave privada: {private_key.secret.hex()}")
print(f"Chave pública (uncompressed): {public_key.format(compressed=False).hex()}")

# Assinar mensagem
message = b"Transferir 5 BTC para 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
signature = private_key.sign(message, hasher=hashlib.sha256)

print(f"Assinatura (DER): {signature.hex()}")

# Verificar
verified = public_key.verify(signature, message, hasher=hashlib.sha256)
print(f"Assinatura válida: {verified}")
```

#### Exemplo 5 – ECDSA em Java (Bouncy Castle)

```java
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.util.Base64;

public class ECDSAExample {
    public static void main(String[] args) throws Exception {
        // Gerar par de chaves (P-256)
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
        ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
        keyGen.initialize(ecSpec);
        KeyPair keyPair = keyGen.generateKeyPair();
        
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        
        // Assinar
        Signature sig = Signature.getInstance("SHA256withECDSA");
        sig.initSign(privateKey);
        byte[] message = "Mensagem secreta".getBytes();
        sig.update(message);
        byte[] signature = sig.sign();
        
        System.out.println("Assinatura (base64): " + Base64.getEncoder().encodeToString(signature));
        
        // Verificar
        sig.initVerify(publicKey);
        sig.update(message);
        boolean isValid = sig.verify(signature);
        System.out.println("Assinatura válida: " + isValid);
    }
}
```

***

### ⚠️ Vulnerabilidades Críticas

#### 1. Reutilização de k (O ERRO MAIS GRAVE)

Se o mesmo `k` for usado para duas assinaturas diferentes, a chave privada é **recuperada instantaneamente**.

```python
# Duas assinaturas com mesmo k
s1 = k⁻¹ × (z1 + r×d) mod n
s2 = k⁻¹ × (z2 + r×d) mod n

# Subtraindo:
s1 - s2 = k⁻¹ × (z1 - z2) mod n
k = (z1 - z2) / (s1 - s2) mod n
d = (s1×k - z1) / r mod n  # Chave privada recuperada!
```

**Casos reais:**

* **PlayStation 3 (2010):** Sony usou mesmo k para todas as assinaturas → chave privada extraída
* **Bitcoin Android (2013):** Gerador randômico quebrado → k repetido → bitcoins roubados

#### 2. k Fraco ou Previsível

Se `k` for muito pequeno ou previsível, a chave pode ser recuperada.

```python
# k pequeno (ex: 1, 2, 3...)
# Ataque de força bruta é possível

# Solução: usar gerador criptograficamente seguro
k = secrets.randbelow(n-1) + 1  # Python
k = SecureRandom().nextInt(n-1) + 1  # Java
```

#### 3. Ataque de Lattice (Bleichenbacher)

Para curvas com `n` ligeiramente menor que a potência de 2 (ex: P-256).

#### 4. Timing Attack

Implementações que não são constant-time podem vazar o valor de `k`.

#### 5. Falta de Validação de Pontos

Pontos maliciosos podem levar à recuperação da chave.

***

### 🛡️ Melhores Práticas

#### 1. Gerador de k Seguro

```python
import secrets

# ✅ Correto - Gerador criptograficamente seguro
k = secrets.randbelow(n-1) + 1

# ❌ Errado - Gerador previsível
import random
k = random.randint(1, n-1)  # Não usar!

# ❌ Errado - k fixo
k = 12345  # NUNCA!
```

#### 2. Determinístico (RFC 6979)

Para evitar problemas com RNG, use **RFC 6979** (k derivado deterministicamente da chave + mensagem).

```python
# RFC 6979 - k = HMAC(key, message)
# Garante que mesmo k não será repetido (mesma mensagem = mesma assinatura)

# OpenSSL suporta com flag -sigopt
openssl dgst -sha256 -sign key.pem -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 ...
```

#### 3. Tamanhos Mínimos

```bash
# Curvas recomendadas
# ✅ P-256 (128 bits de segurança) - Mínimo para hoje
# ✅ P-384 (192 bits) - Para alto nível
# ✅ secp256k1 - Para blockchain

# ❌ Evitar curvas pequenas
# P-192 (96 bits) - Quebrada
# P-224 (112 bits) - Quase quebrada
```

#### 4. Validação de Assinaturas

```python
# Sempre validar r e s antes de processar
def validate_signature(r, s, n):
    if not (1 <= r <= n-1 and 1 <= s <= n-1):
        raise ValueError("Assinatura inválida")
```

***

### 🔄 ECDSA vs Outros Algoritmos

| Característica                  | ECDSA                 | RSA                   | EdDSA (Ed25519) |
| ------------------------------- | --------------------- | --------------------- | --------------- |
| **Base**                        | ECC                   | Fatoração             | ECC (Edwards)   |
| **Tamanho chave (128 bits)**    | 256 bits              | 3072 bits             | 256 bits        |
| **Tamanho assinatura**          | 64 bytes              | 256 bytes             | 64 bytes        |
| **Velocidade (assinar)**        | Rápida                | Lenta                 | Muito rápida    |
| **Velocidade (verificar)**      | Média                 | Rápida                | Rápida          |
| **Determinístico (RFC 6979)**   | Sim (opcional)        | Sim                   | Sim (nativo)    |
| **Resistente a timing attacks** | Implementação depende | Implementação depende | ✅ Sim (nativo)  |
| **Aleatoriedade necessária**    | Sim (k)               | Não                   | Não             |
| **Uso no Bitcoin**              | ✅ Sim                 | ❌                     | ❌               |
| **Uso no TLS 1.3**              | ✅ Sim                 | ❌ (só assinatura)     | ✅ Sim           |

***

### 📜 Casos Reais

| Ano      | Caso                        | Problema                       | Impacto                                  |
| -------- | --------------------------- | ------------------------------ | ---------------------------------------- |
| **2010** | PlayStation 3               | Mesmo k para todas assinaturas | Chave privada extraída, homebrew ativado |
| **2013** | Bitcoin Android (Random)    | Gerador randômico quebrado     | Milhares de bitcoins roubados            |
| **2015** | Freenet                     | k previsível (gerador fraco)   | Chaves recuperadas                       |
| **2017** | Java ECDSA (CVE-2017-15346) | Cache timing attack            | Vazamento de chave                       |
| **2019** | Libgcrypt (CVE-2019-13627)  | Vazamento de bits de k         | Chave recuperada                         |

***

### 🎯 Resumo Rápido

| Ponto                   | Resumo                                |
| ----------------------- | ------------------------------------- |
| **Função**              | Assinatura digital (não cifragem)     |
| **Base**                | Curvas elípticas + logaritmo discreto |
| **Curva padrão**        | P-256 (NIST), secp256k1 (Bitcoin)     |
| **Tamanho assinatura**  | 64 bytes (P-256)                      |
| **ERRO CRÍTICO**        | Reutilizar k → chave privada exposta  |
| **Melhor prática**      | RFC 6979 (k determinístico)           |
| **Alternativa moderna** | Ed25519 (EdDSA)                       |

***

### 🔗 Links Úteis

* [FIPS 186-5 (NIST) - Digital Signature Standard](https://csrc.nist.gov/publications/detail/fips/186/5/final)
* [RFC 6979 - Deterministic ECDSA](https://tools.ietf.org/html/rfc6979)
* [SECG - SEC2 (Recommended Curves)](https://www.secg.org/sec2-v2.pdf)
* [PlayStation 3 Hack - k Reuse](https://events.ccc.de/congress/2010/Fahrplan/events/4087.en.html)
* [Bitcoin Android Hack (Random Number Generator)](https://bitcoin.org/en/alert/2013-08-11-android)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xmorte.gitbook.io/bibliadopentestbr/conceitos/criptografia/assimetrica/ecc-elliptic-curve-cryptography/ecdsa-elliptic-curve-digital-signature-algorithm.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
