o
    2Ji'                     @   sr  d Z ddlZddlZddlZddlZddlmZ ddlmZ z
ddl	m
Z
 dZW n ey3   dZY nw zddlmZ dd	lmZ dZW n eyS   dZddlZY nw d,dedefddZd-dededefddZdedefddZdedefddZd.dededededef
ddZd/d ed!ee defd"d#Zd$edefd%d&ZG d'd( d(Zd)d* Ze d+kre  dS dS )0ul  
Rook Key Derivation Module

Derives all system keys from a BIP39 mnemonic + optional key file + Google Drive folder ID.

Derivation chain:
    mnemonic → BIP39 seed (512-bit)
    seed + salt(keyfile_hash, folder_id) → HKDF-SHA256 → purpose-specific keys

Three independent keys from one root:
    info="bitwarden-master"  → Vaultwarden master password (Base85)
    info="luks-container"    → LUKS2 passphrase (hex)
    info="backup-aes-key"    → AES-256-GCM key for backups (raw bytes)

Usage:
    from keygen import RookKeyDerivation

    kd = RookKeyDerivation(
        mnemonic="abandon abandon abandon ... about",
        folder_id="1a2b3c4d5e6f",
        keyfile_path="/path/to/photo.jpg",  # optional
    )

    print(kd.bitwarden_password)   # Base85 string
    print(kd.luks_passphrase)      # hex string
    backup_key = kd.backup_key     # 32 raw bytes
    N)Path)Optional)MnemonicTF)HKDF)hashes   strengthreturnc                 C   s   t rtd}|| S td)uG   Generate a BIP39 mnemonic. strength=128 → 12 words, 256 → 24 words.englishzTpython-mnemonic required for mnemonic generation. Install with: pip install mnemonic)HAS_MNEMONIC_LIBr   generateImportError)r   m r   3/home/geodesix/Jetson/tests/../src/crypto/keygen.pygenerate_mnemonic>   s   
r    mnemonic
passphrasec                 C   sR   t rtd}|| stdt| |S | d}d| d}td||dS )z>Convert BIP39 mnemonic to 512-bit seed via PBKDF2-HMAC-SHA512.r
   Invalid BIP39 mnemonicutf-8r   sha512i   )r   r   check
ValueErrorto_seedencodehashlibpbkdf2_hmac)r   r   r   mnemonic_bytessaltr   r   r   mnemonic_to_seedJ   s   

r    c                 C   s*   t r	td| S |   }t|dv S )z#Check if a mnemonic is valid BIP39.r
   )               )r   r   r   stripsplitlen)r   wordsr   r   r   validate_mnemonicX   s   r*   pathc                 C   s^   t  }t| d}	 |d}|sn|| qW d   | S 1 s&w   Y  | S )z%SHA256 hash of a key file's contents.rbTi   N)r   sha256openreadupdatedigest)r+   hfchunkr   r   r   hash_keyfilee   s   


r5       ikmr   infolengthc           
      C   s   t rtt |||d}|| S |sd}t|| tj	 }|d d }d}d}t
d|d D ]}	t||| t|	g tj	 }||7 }q0|d| S )zDerive a key using HKDF-SHA256.)	algorithmr9   r   r8   s                                       r6          N)HAS_CRYPTOGRAPHYr   r   SHA256derivehmacnewr   r-   r1   rangebytes)
r7   r   r8   r9   hkdfprknokmtir   r   r   _hkdf_deriveu   s$   
"
rK   	folder_idkeyfile_hashc                 C   s*   |r||  d }t| S |  dS )zGBuild the combined HKDF salt from folder ID and optional key file hash.r   )r   r   r-   r1   )rL   rM   combinedr   r   r   
build_salt   s   
rO   datac                 C   s   ddl }|| dS )z(Encode bytes as Base85 (ASCII85) string.r   Nascii)base64	b85encodedecode)rP   rR   r   r   r   base85_encode   s   rU   c                   @   s~   e Zd ZdZ	ddededee fddZedefd	d
ZedefddZ	ede
fddZedefddZdd ZdS )RookKeyDerivationu3  
    Derives all Hermes system keys from a BIP39 mnemonic.

    Attributes:
        bitwarden_password: str — Base85-encoded Vaultwarden master password
        luks_passphrase: str — Hex-encoded LUKS2 container passphrase
        backup_key: bytes — 32-byte AES-256-GCM key for backup encryption
    Nr   rL   keyfile_pathc                 C   s   t |std|stdt|| _d }|r(t| s$td| t|}t||| _	t
| j| j	dd| _t
| j| j	dd| _t
| j| j	dd| _d S )Nr   z"Google Drive folder ID is requiredzKey file not found: s   bitwarden-masterr6   s   luks-containers   backup-aes-key)r*   r   r    _seedr   existsFileNotFoundErrorr5   rO   _saltrK   _bw_key	_luks_key_backup_key)selfr   rL   rW   rM   r   r   r   __init__   s   
zRookKeyDerivation.__init__r	   c                 C   s
   t | jS )uE   Vaultwarden master password (Base85-encoded, 32 bytes → ~40 chars).)rU   r\   r_   r   r   r   bitwarden_password      
z$RookKeyDerivation.bitwarden_passwordc                 C   
   | j  S )u@   LUKS2 container passphrase (hex-encoded, 32 bytes → 64 chars).)r]   hexra   r   r   r   luks_passphrase   rc   z!RookKeyDerivation.luks_passphrasec                 C   s   | j S )z5AES-256-GCM key for backup encryption (32 raw bytes).)r^   ra   r   r   r   
backup_key   s   zRookKeyDerivation.backup_keyc                 C   rd   )z9AES-256-GCM key as hex string (for display/verification).)r^   re   ra   r   r   r   backup_key_hex   rc   z RookKeyDerivation.backup_key_hexc                 C   sd   ddl }dD ])}t| |d}|r)t|tr)|t|t| t| dt| t	| |d qdS )z'Overwrite sensitive material in memory.r   N)rX   r[   r\   r]   r^   )
ctypesgetattr
isinstancerD   memsetidsys	getsizeofr(   setattr)r_   ri   attrvalr   r   r   wipe   s   (zRookKeyDerivation.wipeN)__name__
__module____qualname____doc__strr   r`   propertyrb   rf   rD   rg   rh   rs   r   r   r   r   rV      s&    
rV   c                  C   s   ddl } | jdd}|jdd}|jddd	}|jd
tddgdd |jddd	}|jdddd |jdddd |jddd	 |jdddd |jddd	}|jddd	 | }|jdkr|jdkrfd nd!}t	|}t
d"|j d# | }	t|	d$D ]\}
}t
d%|
d&d'|  q~t
d( dS |jdkrt|j|j|jd)}t
d* t
d+|j  t
d,|jpd-  |jrt
d. t
d/|j  t
d0|j  t
d1|j  nt
d2 |  dS |jdkrt|j}t
d3|rd4nd5  dS |  dS )6zCLI for testing key derivation.r   NzRook Key Derivation)descriptioncommand)destr   zGenerate a new BIP39 mnemonic)helpz--wordsr!   r%   )typechoicesdefaultr@   zDerive keys from mnemonicz
--mnemonicTzBIP39 mnemonic (quoted))requiredr~   z--folder-idzGoogle Drive folder IDz	--keyfilezOptional key file pathz--show-keys
store_truezPrint derived keys (DANGER))actionr~   validatezCheck if a mnemonic is validr   zBIP39 mnemonic to validater      z
Generated z-word mnemonic:
r=   z  2z. z+
WRITE THESE DOWN. Do not store digitally.
)r   rL   rW   z
Key derivation successful.z  Folder ID:    z  Key file:     noneu%   
  *** SENSITIVE — DO NOT SHARE ***z  Bitwarden pw: z  LUKS phrase:  z  Backup key:   z=
  Keys derived but not displayed. Use --show-keys to reveal.zMnemonic is VALIDINVALID)argparseArgumentParseradd_subparsers
add_parseradd_argumentint
parse_argsr|   r)   r   printr'   	enumeraterV   r   rL   keyfile	show_keysrb   rf   rh   rs   r*   
print_help)r   parsersubgenr@   rr   argsr   r   r)   rJ   wkdvalidr   r   r   main   sR   



r   __main__)r   )r   )r6   rt   )!rx   r   ossecretsrn   pathlibr   typingr   r   r   r   r   'cryptography.hazmat.primitives.kdf.hkdfr   cryptography.hazmat.primitivesr   r>   rA   r   ry   r   rD   r    boolr*   r5   rK   rO   rU   rV   r   ru   r   r   r   r   <module>   sB   
 
J;
