NIP-49: Private Key Encryption

This NIP defines a method by which clients can encrypt (and decrypt) a user's private key with a password.

Encrypt a secret key

Firstly, parse or generate a secret key:

Rust
let secret_key: SecretKey = SecretKey::parse("3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683")?;
Python
secret_key = SecretKey.parse("3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683")
JavaScript
let secretKey: SecretKey = SecretKey.parse("3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683");
Kotlin
val secretKey: SecretKey = SecretKey.parse("3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683")
Swift
let secretKey = try SecretKey.parse(secretKey: "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683")
Flutter
SecretKey secretKey = SecretKey.parse(secretKey: "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683");

Now that we have the SecretKey, we can encrypt it:

Rust
let password: &str = "nostr";
let encrypted: EncryptedSecretKey = secret_key.encrypt(password)?;
Python
password = "nostr"
encrypted = secret_key.encrypt(password)
JavaScript
let password: string = "nostr";
let encrypted: EncryptedSecretKey = secretKey.encrypt(password);
Kotlin
val password = "nostr"
val encrypted: EncryptedSecretKey = secretKey.encrypt(password)
Swift
let password = "nostr"
let encrypted = try secretKey.encrypt(password: password)
Flutter
final password = "nostr";
EncryptedSecretKey encrypted = secretKey.encrypt(password: password);

In some cases, you may want to customize some encryption values:

Rust
let encrypted: EncryptedSecretKey = EncryptedSecretKey::new(&secret_key, password, 12, KeySecurity::Weak)?;
Python
encrypted_custom = EncryptedSecretKey(secret_key, password, 12, KeySecurity.WEAK)
JavaScript
let encryptedCustom: EncryptedSecretKey = new EncryptedSecretKey(secretKey, password, 12, KeySecurity.Weak);
Kotlin
val encryptedCustom = EncryptedSecretKey(secretKey, password, 12u, KeySecurity.WEAK)
Swift
let encryptedCustom = try EncryptedSecretKey(secretKey: secretKey, password: password, logN: 12, keySecurity: KeySecurity.weak)
Flutter
EncryptedSecretKey encryptedCustom = EncryptedSecretKey(secretKey: secretKey, password: password, logN: 12, keySecurity: EncryptedSecretKeySecurity.weak);

Decrypt a secret key

Let's start by parsing the ncryptsec string:

Rust
let encrypted: EncryptedSecretKey = EncryptedSecretKey::from_bech32("ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p")?;
Python
encrypted = EncryptedSecretKey.from_bech32("ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p")
JavaScript
let encrypted: EncryptedSecretKey = EncryptedSecretKey.fromBech32("ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p");
Kotlin
val encrypted: EncryptedSecretKey = EncryptedSecretKey.fromBech32("ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p")
Swift
let encrypted = try EncryptedSecretKey.fromBech32(bech32: "ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p")
Flutter
EncryptedSecretKey encrypted = EncryptedSecretKey.fromBech32(bech32: "ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p");

Now you can decrypt the secret key:

Rust
let secret_key: SecretKey = encrypted.to_secret_key("nostr")?;
Python
secret_key = encrypted.to_secret_key("nostr")
JavaScript
let secretKey: SecretKey = encrypted.toSecretKey("nostr");
Kotlin
val secretKey: SecretKey = encrypted.toSecretKey(password = "nostr")
Swift
let secretKey = try encrypted.toSecretKey(password: "nostr")
Flutter
SecretKey secretKey = encrypted.decrypt(password: "nostr");

Full example

Here’s the full example that includes all the steps:

Rust
use nostr_sdk::prelude::*;

pub fn encrypt() -> Result<()> {
    let secret_key: SecretKey = SecretKey::parse("3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683")?;

    let password: &str = "nostr";
    let encrypted: EncryptedSecretKey = secret_key.encrypt(password)?;
    
    println!("Encrypted secret key: {}", encrypted.to_bech32()?);

    let encrypted: EncryptedSecretKey = EncryptedSecretKey::new(&secret_key, password, 12, KeySecurity::Weak)?;

    println!("Encrypted secret key (custom): {}", encrypted.to_bech32()?);

    Ok(())
}

pub fn decrypt() -> Result<()> {
    let encrypted: EncryptedSecretKey = EncryptedSecretKey::from_bech32("ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p")?;

    let secret_key: SecretKey = encrypted.to_secret_key("nostr")?;

    println!("Decrypted secret key: {}", secret_key.to_bech32()?);

    Ok(())
}
Python
from nostr_sdk import SecretKey, EncryptedSecretKey, KeySecurity

def encrypt():
    secret_key = SecretKey.parse("3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683")

    password = "nostr"
    encrypted = secret_key.encrypt(password)

    print(f"Encrypted secret key: {encrypted.to_bech32()}")

    encrypted_custom = EncryptedSecretKey(secret_key, password, 12, KeySecurity.WEAK)

    print(f"Encrypted secret key (custom): {encrypted_custom.to_bech32()}")

def decrypt():
    encrypted = EncryptedSecretKey.from_bech32("ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p")

    secret_key = encrypted.to_secret_key("nostr")

    print(f"Decrypted secret key: {secret_key.to_bech32()}")

JavaScript
import {EncryptedSecretKey, KeySecurity, loadWasmSync, SecretKey} from "@rust-nostr/nostr-sdk";

function encrypt() {
    let secretKey: SecretKey = SecretKey.parse("3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683");

    let password: string = "nostr";
    let encrypted: EncryptedSecretKey = secretKey.encrypt(password);

    console.log("Encrypted secret key:", encrypted.toBech32());

    let encryptedCustom: EncryptedSecretKey = new EncryptedSecretKey(secretKey, password, 12, KeySecurity.Weak);

    console.log("Encrypted secret key (custom):", encryptedCustom.toBech32());
}

function decrypt() {
    let encrypted: EncryptedSecretKey = EncryptedSecretKey.fromBech32("ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p");

    let secretKey: SecretKey = encrypted.toSecretKey("nostr");

    console.log("Decrypted secret key:", secretKey.toBech32());
}

loadWasmSync();
encrypt();
decrypt();
Kotlin
import rust.nostr.sdk.*

fun encrypt() {
    val secretKey: SecretKey = SecretKey.parse("3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683")

    val password = "nostr"
    val encrypted: EncryptedSecretKey = secretKey.encrypt(password)

    println("Encrypted secret key: ${encrypted.toBech32()}")

    val encryptedCustom = EncryptedSecretKey(secretKey, password, 12u, KeySecurity.WEAK)

    println("Encrypted secret key (custom): ${encryptedCustom.toBech32()}")
}

fun decrypt() {
    val encrypted: EncryptedSecretKey = EncryptedSecretKey.fromBech32("ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p")

    val secretKey: SecretKey = encrypted.toSecretKey(password = "nostr")

    println("Decrypted secret key: ${secretKey.toBech32()}")
}

fun main() {
    encrypt()
    decrypt()
}
Swift
import Foundation
import NostrSDK

func encrypt() throws {
    let secretKey = try SecretKey.parse(secretKey: "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683")

    let password = "nostr"
    let encrypted = try secretKey.encrypt(password: password)

    print("Encrypted secret key: \(try encrypted.toBech32())")

    let encryptedCustom = try EncryptedSecretKey(secretKey: secretKey, password: password, logN: 12, keySecurity: KeySecurity.weak)

    print("Encrypted secret key (custom): \(try encryptedCustom.toBech32())")
}

func decrypt() throws {
    let encrypted = try EncryptedSecretKey.fromBech32(bech32: "ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p")

    let secretKey = try encrypted.toSecretKey(password: "nostr")

    print("Decrypted secret key: \(try secretKey.toBech32())")
}
Flutter
import 'package:nostr_sdk/nostr_sdk.dart';

void encrypt() {
  SecretKey secretKey = SecretKey.parse(secretKey: "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683");

  final password = "nostr";
  EncryptedSecretKey encrypted = secretKey.encrypt(password: password);

  print("Encrypted secret key: ${encrypted.toBech32()}");

  EncryptedSecretKey encryptedCustom = EncryptedSecretKey(secretKey: secretKey, password: password, logN: 12, keySecurity: EncryptedSecretKeySecurity.weak);

  print("Encrypted secret key (custom): ${encryptedCustom.toBech32()}");
}

void restore() {
  EncryptedSecretKey encrypted = EncryptedSecretKey.fromBech32(bech32: "ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p");

  SecretKey secretKey = encrypted.decrypt(password: "nostr");

  print("Decrypted secret key: ${secretKey.toBech32()}");
}