Corporate Private Key Management System Development

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1All 1305 services
Corporate Private Key Management System Development
Complex
~1-2 weeks
Frequently Asked Questions

Blockchain Development Services

Blockchain Development Stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1349
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1247
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    949
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1183
  • image_logo-advance_0.webp
    B2B Advance company logo design
    642
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    921

Private key is the single source of truth in blockchain. No recovery password, no support desk, no transaction rollback. Key compromise = permanent loss of all assets under its control. According to analytics, over 50% of DeFi protocol hacks result from private key leaks, with annual damage exceeding $2 billion. Yet most organizations store keys in .env files on servers or, worse, in developers' personal wallets. In real projects we've seen keys hidden in Git comments and Docker layers — each such finding eventually leads to an incident. We offer end-to-end development of a corporate key management system — from current threat landscape audit to HSM deployment and signing policies. Our engineers have 10+ years of experience in cryptography and blockchain infrastructure. Let's explore which architectures truly protect assets.

What threats does corporate key management address?

Before choosing technologies, you need to clearly define threats.

  • External attacker: server breach, credential leakage, SQL injection in adjacent systems. The attacker gains access to the execution environment.
  • Malicious insider: an employee with legitimate access attempts to use the key unauthorized or steal it.
  • Infrastructure failure: server with key goes down at the worst possible moment. Replication without compromising security is required.
  • Supply chain attack: compromised dependency, modified Docker image, BGP hijack by cloud provider.

Different threats require different protective measures. There is no single correct solution — there is a set of tools with different trade-offs between security and convenience.

Key Protection Levels

Hardware Security Modules (HSM)

HSM is a physical device that stores key material and performs cryptographic operations inside a tamper-proof enclave. The key never leaves the device in plaintext. HSM provides 100x stronger protection against key extraction compared to software storage. Average signing time is less than 10 ms, availability is 99.99%.

Cloud options: AWS CloudHSM, Azure Dedicated HSM, Google Cloud HSM. On-premise: Thales Luna, Entrust nShield. For blockchain, YubiHSM 2 is often used (affordable option around $500).

# Interaction with HSM via PKCS#11 (standard interface)
import pkcs11
from pkcs11 import Mechanism, KeyType, ObjectClass

def sign_ethereum_transaction_with_hsm(
    tx_hash: bytes,
    slot_id: int,
    pin: str,
    key_label: str
) -> tuple[int, int, int]:
    """
    Signs a transaction hash with a private key inside HSM
    Returns (v, r, s) signature components
    """
    lib = pkcs11.lib('/usr/lib/softhsm/libsofthsm2.so')  # or path to real HSM
    token = lib.get_token(slot_id=slot_id)
    
    with token.open(user_pin=pin) as session:
        # Find key by label
        private_key = session.get_key(
            object_class=ObjectClass.PRIVATE_KEY,
            key_type=KeyType.EC,
            label=key_label
        )
        
        # Signing happens inside HSM, key never exported
        signature = private_key.sign(tx_hash, mechanism=Mechanism.ECDSA)
        
        # Convert DER signature to (r, s)
        r, s = decode_ecdsa_signature(signature)
        v = determine_recovery_id(tx_hash, r, s)
        
        return v, r, s

def generate_key_in_hsm(session, label: str) -> None:
    """Generates a key pair inside HSM"""
    # Key is generated inside HSM and never leaves in plainview
    pub, priv = session.generate_keypair(
        KeyType.EC,
        key_length=256,
        curve='secp256k1',
        public_template={
            pkcs11.Attribute.LABEL: label,
            pkcs11.Attribute.TOKEN: True,
            pkcs11.Attribute.VERIFY: True,
        },
        private_template={
            pkcs11.Attribute.LABEL: label,
            pkcs11.Attribute.TOKEN: True,
            pkcs11.Attribute.PRIVATE: True,
            pkcs11.Attribute.SENSITIVE: True,
            pkcs11.Attribute.SIGN: True,
            pkcs11.Attribute.EXTRACTABLE: False,
        }
    )

Multi-Party Computation (MPC)

MPC is a technology where the key never exists in full form on a single device. Several participants store key shares (shards), and transaction signing occurs through a cryptographic protocol without assembling the full key. Signing takes ~200 ms, gas saved up to 30% compared to multisig.

Used in Fireblocks, Zengo, Qredo, Coinbase Prime. Pre-standard protocols: GG18/GG20 (Lindell et al.), FROST (Flexible Round-Optimized Schnorr Threshold Signatures).

MPC signing scheme (simplified):

Participant A has: key_share_A
Participant B has: key_share_B  
Participant C has: key_share_C

For signing, any 2 of 3 are needed (2-of-3 scheme):

1. A and B start the protocol
2. Exchange commitments (without revealing shards)
3. Compute partial signatures
4. Aggregate: signature = combine(partial_A, partial_B)
5. Result — valid ECDSA signature
6. key_share_A and key_share_B NEVER existed on the same device

Advantages of MPC over on-chain multisig: the signature looks like a regular single-sig transaction (less gas, does not reveal governance structure), policy enforcement off-chain (any rules can be added without changing the smart contract).

How to choose between MPC and Multisig

It's important not to confuse MPC threshold signatures with on-chain multisig (Gnosis Safe). These are different approaches with different trade-offs:

Characteristic MPC (TSS) On-chain Multisig (Gnosis Safe)
Gas cost Standard signature Depends on scheme (higher)
Transparency Governance structure not visible All signers public on-chain
Off-chain policy Full flexibility None
Signing audit Off-chain log On-chain history
Shard recovery More complex Simple (add/remove owner)
Maturity Relatively new Battle-tested for years

For most organizations: Gnosis Safe for large cold storage (transparency more important than gas), MPC for operational hot wallets (speed and policy flexibility).

Transaction Authorization Policies

Keys are only part of the system. Equally important is defining who can sign transactions, when, and under what conditions.

Policy Engine

interface TransactionPolicy {
    id: string;
    name: string;
    conditions: PolicyCondition[];
    requiredApprovals: number;
    approvers: string[];
    maxAmountUsd?: number;
    allowedContracts?: string[];
    allowedChains?: number[];
    timeRestrictions?: TimeRestriction;
}

interface PolicyCondition {
    type: 'amount' | 'contract' | 'method' | 'time' | 'chain';
    operator: 'eq' | 'lt' | 'gt' | 'in' | 'not_in';
    value: unknown;
}

class PolicyEngine {
    private policies: TransactionPolicy[];
    
    async evaluateTransaction(tx: PendingTransaction): Promise<PolicyResult> {
        const matchingPolicies = this.findMatchingPolicies(tx);
        
        if (matchingPolicies.length === 0) {
            return { 
                allowed: false, 
                reason: 'No matching policy',
                requiresManualReview: true 
            };
        }
        
        // Take the most restrictive applicable policy
        const strictestPolicy = this.getMostRestrictivePolicy(matchingPolicies);
        
        // Check limits
        if (strictestPolicy.maxAmountUsd) {
            const txValueUsd = await this.getTransactionValueUsd(tx);
            if (txValueUsd > strictestPolicy.maxAmountUsd) {
                return {
                    allowed: false,
                    reason: `Exceeds limit: $${txValueUsd} > $${strictestPolicy.maxAmountUsd}`,
                    requiresApproval: true,
                    approvers: strictestPolicy.approvers
                };
            }
        }
        
        // Check contract whitelist
        if (strictestPolicy.allowedContracts && 
            tx.to && 
            !strictestPolicy.allowedContracts.includes(tx.to.toLowerCase())) {
            return {
                allowed: false,
                reason: 'Contract not in whitelist',
                requiresManualReview: true
            };
        }
        
        return { allowed: true, policy: strictestPolicy };
    }
}

Authorization Levels

Typical corporate hierarchy:

Level Transaction Amount Required Confirmations
Automatic up to $1,000 No human
Single person $1,000–$50,000 One employee
Multi-person $50,000–$500,000 M of N confirmations
Board-level over $500,000 Committee, physical meeting

Key Lifecycle Management

Key lifecycle: generation → registration → operational use → rotation → revocation. Each stage requires separate procedures.

Generation must occur in a trusted environment (HSM, air-gapped machine). Entropy source is verified. Generation is documented with witness signatures.

Backup sharding: keys are backed up using Shamir's Secret Sharing. 3-of-5 scheme: five shards distributed across different physical locations, three sufficient for recovery.

from secretsharing import PlaintextToHexSecretSharer

def backup_private_key(private_key_hex: str, shares: int = 5, threshold: int = 3) -> list[str]:
    """
    Splits a private key into N shards, of which threshold are sufficient for recovery
    Shards are stored separately: different people, different physical locations
    """
    shards = PlaintextToHexSecretSharer.split_secret(
        private_key_hex,
        threshold,
        shares
    )
    return shards

def recover_private_key(shards: list[str]) -> str:
    """Recovers the key from any threshold shards"""
    return PlaintextToHexSecretSharer.recover_secret(shards)

# Backup procedure:
# 1. Air-gapped machine, no network
# 2. Generate 5 shards
# 3. Each shard on a separate iron key + paper backup
# 4. Envelopes sealed, signed by witnesses
# 5. Stored in different safes (office, bank safe deposit box, home safe of key employees)

How Shamir's Secret Sharing Works

Shamir's Secret Sharing is an algorithm that splits a secret into shares (shards) such that recovery requires a threshold number of shares. In a 3-of-5 scheme, any 3 shares allow reconstructing the original key, but 2 shares yield no information. This provides fault tolerance and security: loss of one or two shards is not critical, and theft of less than three is useless.

Mathematical details of Shamir's scheme

Secret S is split into n shares using a polynomial of degree k-1. Coefficients are random, the constant term equals S. Recovery requires k points, through which the polynomial is interpolated and the constant term found.

Key rotation: planned (once a year) and unplanned (suspicion of compromise, employee with access leaves). For on-chain contracts, requires changing the owner via multisig.

Revocation: upon compromise, immediate transfer of assets to a new key. You cannot simply "block" a key in the blockchain.

Audit and Monitoring

Every key usage must be logged: who requested signing, what was signed, who authorized, timestamp, IP, device fingerprint.

interface KeyUsageEvent {
    eventId: string;
    timestamp: Date;
    keyId: string;
    operation: 'sign' | 'derive' | 'export_public' | 'rotate';
    requestedBy: string;      // user ID or service account
    approvedBy: string[];     // if approval was required
    transactionHash?: string; // if transaction
    transactionData?: {
        to: string;
        value: string;
        chainId: number;
        methodSignature?: string;
    };
    policyId: string;
    ipAddress: string;
    deviceId: string;
    approved: boolean;
    rejectionReason?: string;
}

// All events are signed by an HSM audit key — cannot be forged
// Stored in append-only storage (Kafka, CloudTrail, immutable S3 bucket)

Anomalies for alerting: signing outside business hours, atypical destination addresses, transaction volume above historical norm, attempts to sign rejected transactions.

According to the NIST SP 800-57 standard, key management must include full audit of all operations.

Disaster Recovery

A recovery plan must be documented and regularly tested (tabletop exercises). Scenarios: loss of one server with key, loss of data center, compromise of one shard, departure of key keeper.

RTO (Recovery Time Objective) for different levels:

Level Recovery Time Objective
Hot wallet Minutes (automatic failover)
Cold storage Hours (multi-person procedure)
Full key change 24–48 hours

Regular tests: quarterly recovery simulation in staging environment. Without testing, a recovery plan is just a document.

What's Included in the Work

  • Audit of current key management scheme and threat landscape
  • Architecture design (HSM, MPC, policy engine)
  • Development and configuration of components
  • Integration with existing tools (AWS, Hashicorp Vault, Kubernetes)
  • Documentation of procedures and recovery plan
  • Team training (key keepers, administrators)
  • Post-deployment support

Stack and Development Timeline

Infrastructure: AWS CloudHSM or YubiHSM 2, Hashicorp Vault (secrets and policy management), Kubernetes for signing services.

MPC libraries: tss-lib (Go, GG20 implementation), ZenGo-X/multi-party-ecdsa (Rust), Fireblocks SDK for enterprise.

Backend: Go or Rust for performance-critical signing service, Node.js/Python for API gateway.

Audit: security audit of the key management system is mandatory, ideally with penetration testing.

Development timeline for a corporate KMS: 4–6 months for a production-grade system with HSM, MPC, and policy engine. Integrating with Gnosis Safe or Fireblocks instead of custom MPC cuts the time in half.

Evaluate your current key management setup — contact us for a free consultation. Order corporate KMS development and receive an architecture review as a gift.

How Do We Find What the Compiler Misses?

When a protocol loses $197M through a flash loan attack on a function that auditors reviewed live — it's not an accident. It's a systemic gap in methodology. Our experience shows: vulnerabilities live in a contract for over a year, while the compiler remains silent. We restructured the audit process to catch such cases before deployment.

What Static Analysis Won't Find?

Slither is the standard first tool. It finds reentrancy, integer overflow (in older Solidity versions), improper use of tx.origin, variable shadowing, uninitialized storage. On a real project, Slither produces dozens of warnings, of which critical ones are 0‑2. The rest is informational noise.

Slither won't find logical vulnerabilities. If withdraw correctly checks balance and correctly updates state, but business logic allows double deduction through two different code paths — Slither stays silent.

Mythril uses symbolic execution: builds a graph of all possible execution paths and searches for reachable states violating properties. Works well on isolated contracts. On a protocol of 20 contracts with cross‑contract calls — path explosion, analysis hangs or returns false positives.

Both tools are mandatory as a first pass. But they don't replace manual analysis.

Fuzzing: Where Echidna and Foundry Find Real Bugs

Echidna is a property‑based fuzzer from Trail of Bits. The idea: formulate contract invariants as Solidity functions (echidna_invariant), Echidna generates random call sequences and tries to break the invariant.

Example invariant for a lending protocol:

function echidna_total_assets_ge_liabilities() public view returns (bool) {
    return totalAssets() >= totalLiabilities();
}

Echidna will find a sequence deposit → borrow → liquidate → repay that violates this invariant. You can't build such a case manually — too many combinations.

Foundry fuzzing (forge test --fuzz-runs 100000) is easier to integrate if the team is already on Foundry. Supports stateful fuzzing via invariant tests. In a real project: auditing a vault contract, Foundry fuzzed for 40 minutes and found an edge case where maxWithdraw returned a value larger than actual balance at a specific shares/assets ratio after several donations. Hardhat unit tests missed it — they didn't have that combination of parameters.

Medusa (from Trail of Bits, newer than Echidna) supports corpus‑guided fuzzing and runs faster on large contracts. If the codebase exceeds 5000 lines of Solidity — we look at Medusa.

How Invariants Help Identify Critical Vulnerabilities

Formal verification proves that the contract satisfies specifications for all possible inputs — not for N random ones, but mathematically for all. Tools: Certora Prover, K Framework, Halmos.

Certora works with CVL (Certora Verification Language): write rules and invariants, the Prover translates them into SMT formulas and checks via Z3/CVC5. MakerDAO, Aave, Uniswap use Certora in CI/CD pipeline — every PR is automatically verified.

Limitations: doesn't work with unbounded loops, struggles with hash functions and signature verification. For contracts with simple math (AMM, lending) — excellent. For contracts with arbitrary external calls — difficult to write sufficiently complete specifications.

Formal verification makes sense for contracts that: manage over $50M, are rarely updated, have clearly formalizable invariants. For fast‑iterating products — the cost‑benefit ratio doesn't favor verification.

What Attack Vectors Do Junior Auditors Miss?

Storage collision in proxy pattern. Transparent proxy and UUPS use specific slots for implementation address (EIP‑1967). If an implementation accidentally declares a variable in slot 0 that overlaps with proxy storage — we get silent override. Slither won't catch this if proxy and implementation are in different files.

Read‑only reentrancy. Classic reentrancy guard protects against state changes during recursive calls. But if an external contract reads state via a view function mid‑transaction — guard doesn't help. Years ago, Curve pools became an attack vector precisely through this: an external protocol read get_virtual_price during a reentrancy‑vulnerable state of Curve.

Oracle manipulation via TWAP. Spot price is a standard target for flash loan attack. TWAP is harder to manipulate, but not impossible: on low‑liquidity Uniswap v2 pairs, TWAP can be shifted over several blocks with enough capital. Proper protection: use Chainlink as primary oracle with TWAP as fallback, with deviation threshold check.

Gas griefing on unbounded loop. A function iterates over an array of users. Attacker adds thousands of addresses with zero balances — the function's gas cost rises to the gas limit, making it inaccessible. Protection: pull pattern instead of push, limit array lengths, batch processing with position tracking.

Front‑running on MEV. Transaction is visible in mempool before inclusion in block. MEV bot sees addLiquidity for a significant amount, inserts its own swap before it (sandwich attack). For AMM this is part of the model. For protocols with price functions — require minAmountOut / deadline parameter and its mandatory verification.

Structure of a Full Audit

  1. Scope definition and automated analysis (1‑2 days). Fix commit hash, compiler version, list of out‑of‑scope items. Run Slither, Mythril, Aderyn. Triage: separate real critical bugs from false positives. Build contract dependency map.

  2. Manual analysis (5‑15 days). Each contract line by line. Special attention: all external and public functions, all transfer/call/delegatecall, all places where state changes before a check or after an external call, all math operations with user inputs. On average, 95% of found vulnerabilities are logical, not technical.

  3. Fuzzing and testing (2‑5 days). Echidna or Foundry invariant tests for critical invariants. Fork mainnet tests — verify behavior in real environment with real oracles. For example, in 4 days fuzzing finds on average 3 edge cases not covered by unit tests.

  4. Report and mitigation. Report with severity (Critical/High/Medium/Low/Informational), attack vector description, PoC code for Critical/High. Developers fix, auditors perform re‑audit of fixes.

Severity Examples Requires re‑audit?
Critical Drain funds, unauthorized ownership transfer Always
High Manipulation, DoS on key functions Always
Medium Incorrect behavior on edge cases Recommended
Low Gas inefficiency, typos in events Optional

Audit in CI/CD

Common practice for mature protocols: Slither and Aderyn run in GitHub Actions on every PR. Certora Prover — on merge to main. This doesn't replace a full audit before deployment, but catches regressions.

# .github/workflows/audit.yml
- name: Run Slither
  uses: crytic/[email protected]
  with:
    target: 'src/'
    slither-args: '--filter-paths "test|mock|script"'
Checklist of mandatory checks before deployment
  • All external functions have access controls (onlyOwner, onlyRole)
  • Use SafeERC20 for external tokens
  • No delegatecall to unknown addresses
  • Reentrancy check in all functions with external calls
  • Presence of minAmountOut and deadline in AMM functions
  • Use of a trusted oracle (Chainlink) with deviation threshold

Audit Tools Comparison

Tool Type of Analysis What It Finds Limitations
Slither Static Reentrancy, integer overflow, access control Misses logical vulnerabilities
Mythril Symbolic execution Reachable states violating properties Path explosion on large codebases
Echidna Fuzzing (property‑based) Invariant violations Requires writing invariants
Certora Formal verification Mathematical proof of properties Doesn't work with hashes/signatures

Deliverables

  • Full report in PDF with CVSS scores for each vulnerability
  • PoC code for all Critical and High (reproducible in test environment)
  • Remediation recommendations with code examples
  • Re‑audit after fixes (up to two iterations)
  • Brief guide for developers on ongoing operation
  • Post‑deployment support for 30 days (consultations and incident analysis)

Timeline

Audit of a simple token or NFT contract — 3‑5 business days. DeFi protocol with lending/AMM — 2‑4 weeks. Full stack with multiple protocols, cross‑chain, proxy upgrades — 4‑8 weeks. Re‑audit of fixes — 3‑7 days separately.

Our team has 7+ years of experience in smart contract security, having audited over 100 projects. We guarantee we won't miss any known attack vectors — we use licensed versions of Slither and best fuzzer configurations. Assess your project — we will analyze your code for free and provide a commercial offer within 2 days. Order an audit with quality guarantee and get a discount on re‑audit for repeat customers.