Commit 763a8fad authored by jan.koester's avatar jan.koester
Browse files

test

parent d50e2cce
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
libnetplus (20260528+23) unstable; urgency=medium

  * ecc: fix mod_n256 infinite loop in ECDSA signing — replace O(2^32)
    repeated subtraction with O(512) bit-by-bit long division
  * tls: implement ECDHE-ECDSA-AES128-GCM-SHA256 cipher suite for
    TLS 1.2 with Let's Encrypt ECDSA certificates
  * tls: fix TLS 1.3 key buffer overflow (16→32 bytes for AES-256)
  * tls: add GCM record encryption/decryption for TLS 1.2

 -- Jan Koester <jan.koester@tuxist.de>  Wed, 28 May 2026 12:00:00 +0200

libnetplus (20260521+22) unstable; urgency=medium

  * x509: add getNotAfter() method for certificate expiry checking
+27 −81
Original line number Diff line number Diff line
@@ -456,27 +456,15 @@ static const u256 SCALAR_N = {{
}};

// Reduction mod n (group order) - used for ECDSA scalar arithmetic
// Uses schoolbook division since n doesn't have a special form like p
// Bit-by-bit long division: O(512) iterations, each O(8) word ops
u256 mod_n256(const u512& in) {
    // For a 512-bit value, we do trial subtraction of n*2^i for i from 256 down to 0
    // This is slow but correct. For production, use Barrett reduction.
    
    // Work with extended precision
    uint64_t t[16];
    for (int i = 0; i < 16; i++) t[i] = in.w[i];
    
    // Reduce: while value >= n * 2^256, subtract n * 2^256
    // Then while value >= n * 2^224, subtract n * 2^224, etc.
    
    // Simple approach: convert to u256, handle overflow with subtraction
    // First, check if high 256 bits are non-zero
    // Fast path: if high 256 bits are zero, just reduce low 256 bits
    bool hasHigh = false;
    for (int i = 8; i < 16; i++) if (t[i] != 0) { hasHigh = true; break; }
    for (int i = 8; i < 16; i++) if (in.w[i] != 0) { hasHigh = true; break; }

    if (!hasHigh) {
        // Just low 256 bits - simple reduction
        u256 r;
        for (int i = 0; i < 8; i++) r.w[i] = (uint32_t)t[i];
        for (int i = 0; i < 8; i++) r.w[i] = in.w[i];
        while (u256_cmp(r, SCALAR_N) >= 0) {
            uint32_t br = 0;
            r = u256_sub_raw(r, SCALAR_N, br);
@@ -484,70 +472,28 @@ u256 mod_n256(const u512& in) {
        return r;
    }

    // Full 512-bit reduction using repeated subtraction
    // This is O(n) in the worst case but works for random inputs
    
    // Compute q ≈ floor(in / n) using high bits estimation
    // Then r = in - q*n and adjust
    
    // For simplicity, use a loop that processes word by word from high to low
    // Each iteration reduces the value by subtracting n shifted appropriately
    
    for (int shift = 256; shift >= 0; shift -= 32) {
        // Check if we can subtract n << shift
        int wordShift = shift / 32;
        
        while (true) {
            // Check if t >= n << shift
            bool canSubtract = false;
            
            // Compare t with n << wordShift
            int topWord = wordShift + 7;
            if (topWord < 16) {
                // Check from top
                bool greater = false;
                bool equal = true;
                for (int i = 15; i >= 0; i--) {
                    uint64_t nShifted = 0;
                    int ni = i - wordShift;
                    if (ni >= 0 && ni < 8) nShifted = SCALAR_N.w[ni];
                    
                    if (t[i] > nShifted) { greater = true; equal = false; break; }
                    if (t[i] < nShifted) { greater = false; equal = false; break; }
                }
                canSubtract = greater || equal;
            }
            
            if (!canSubtract) break;
            
            // Subtract n << wordShift from t
            int64_t borrow = 0;
            for (int i = 0; i < 16; i++) {
                uint64_t nShifted = 0;
                int ni = i - wordShift;
                if (ni >= 0 && ni < 8) nShifted = SCALAR_N.w[ni];
                
                int64_t diff = (int64_t)t[i] - (int64_t)nShifted - borrow;
                if (diff < 0) {
                    diff += 0x100000000LL;
                    borrow = 1;
                } else {
                    borrow = 0;
                }
                t[i] = (uint64_t)diff;
            }
        }
    // Bit-by-bit long division from MSB (bit 511) to LSB (bit 0)
    u256 r = {};
    for (int bit = 511; bit >= 0; bit--) {
        // Shift remainder left by 1
        uint32_t carry = 0;
        for (int i = 0; i < 8; i++) {
            uint32_t newCarry = r.w[i] >> 31;
            r.w[i] = (r.w[i] << 1) | carry;
            carry = newCarry;
        }

    // Result is now in t[0..7]
    u256 r;
    for (int i = 0; i < 8; i++) r.w[i] = (uint32_t)t[i];
        // Bring down next bit from input
        int wordIdx = bit / 32;
        int bitIdx  = bit % 32;
        r.w[0] |= (in.w[wordIdx] >> bitIdx) & 1;

    // Final normalization
    while (u256_cmp(r, SCALAR_N) >= 0) {
        // If carry (value >= 2^256 > n) or r >= n, subtract n
        if (carry || u256_cmp(r, SCALAR_N) >= 0) {
            uint32_t br = 0;
            r = u256_sub_raw(r, SCALAR_N, br);
        }
    }

    return r;
}