Add new packages for cryptographic operations, session management, and I/O handling: - pkg/crypt/chachapoly: ChaCha20-Poly1305 AEAD encryption - pkg/crypt/lthn: Lethean-specific key derivation and encryption - pkg/crypt/rsa: RSA key generation, encryption, and signing - pkg/io/node: CryptoNote node I/O and protocol handling - pkg/io/sigil: Cryptographic sigil generation and verification - pkg/session: Session parsing, HTML rendering, search, and video - internal/cmd/forge: Forgejo auth status command - internal/cmd/session: Session management CLI command Also gitignore build artifacts (bugseti binary, i18n-validate). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
91 lines
2.3 KiB
Go
91 lines
2.3 KiB
Go
package rsa
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/sha256"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"fmt"
|
|
)
|
|
|
|
// Service provides RSA functionality.
|
|
type Service struct{}
|
|
|
|
// NewService creates and returns a new Service instance for performing RSA-related operations.
|
|
func NewService() *Service {
|
|
return &Service{}
|
|
}
|
|
|
|
// GenerateKeyPair creates a new RSA key pair.
|
|
func (s *Service) GenerateKeyPair(bits int) (publicKey, privateKey []byte, err error) {
|
|
if bits < 2048 {
|
|
return nil, nil, fmt.Errorf("rsa: key size too small: %d (minimum 2048)", bits)
|
|
}
|
|
privKey, err := rsa.GenerateKey(rand.Reader, bits)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to generate private key: %w", err)
|
|
}
|
|
|
|
privKeyBytes := x509.MarshalPKCS1PrivateKey(privKey)
|
|
privKeyPEM := pem.EncodeToMemory(&pem.Block{
|
|
Type: "RSA PRIVATE KEY",
|
|
Bytes: privKeyBytes,
|
|
})
|
|
|
|
pubKeyBytes, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to marshal public key: %w", err)
|
|
}
|
|
pubKeyPEM := pem.EncodeToMemory(&pem.Block{
|
|
Type: "PUBLIC KEY",
|
|
Bytes: pubKeyBytes,
|
|
})
|
|
|
|
return pubKeyPEM, privKeyPEM, nil
|
|
}
|
|
|
|
// Encrypt encrypts data with a public key.
|
|
func (s *Service) Encrypt(publicKey, data, label []byte) ([]byte, error) {
|
|
block, _ := pem.Decode(publicKey)
|
|
if block == nil {
|
|
return nil, fmt.Errorf("failed to decode public key")
|
|
}
|
|
|
|
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse public key: %w", err)
|
|
}
|
|
|
|
rsaPub, ok := pub.(*rsa.PublicKey)
|
|
if !ok {
|
|
return nil, fmt.Errorf("not an RSA public key")
|
|
}
|
|
|
|
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, rsaPub, data, label)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to encrypt data: %w", err)
|
|
}
|
|
|
|
return ciphertext, nil
|
|
}
|
|
|
|
// Decrypt decrypts data with a private key.
|
|
func (s *Service) Decrypt(privateKey, ciphertext, label []byte) ([]byte, error) {
|
|
block, _ := pem.Decode(privateKey)
|
|
if block == nil {
|
|
return nil, fmt.Errorf("failed to decode private key")
|
|
}
|
|
|
|
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse private key: %w", err)
|
|
}
|
|
|
|
plaintext, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, priv, ciphertext, label)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decrypt data: %w", err)
|
|
}
|
|
|
|
return plaintext, nil
|
|
}
|