import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 *
 * Beschreibung
 *
 * @version 1.0 vom 05.06.2022
 * @author Rr
 */

public class Wallet {
  
  // Anfang Attribute
  private String Eigentümer;
  private double Kontostand;
  private PrivateKey privKey;
  private PublicKey publKey;
  private String publicKeyBase64;
  private String signaturBase64;
  private String Transaktion;
  // Ende Attribute
  
  public Wallet(String Eigentümer, double Kontostand) {
    this.Eigentümer = Eigentümer;
    this.Kontostand = Kontostand;
    try {
      KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
      ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");  // secp256k1 nur bis JDK 15
      keyGen.initialize(ecSpec);      
      KeyPair kp = keyGen.generateKeyPair();
      privKey = kp.getPrivate();
      publKey = kp.getPublic();

      // encoded with ASN.1/DER, siehe 
      // https://en.wikipedia.org/wiki/ASN.1 und 
      // https://holtstrom.com/michael/tools/asn1decoder.php
      publicKeyBase64 = Base64.getEncoder().encodeToString(publKey.getEncoded());
    } catch(Exception e) {
      System.out.println(e.getMessage());
    } 
  }

  // Anfang Methoden
  public String signieren(String Message) {
    // http://blog.wenzlaff.de/?p=16427
    try {
      Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");
      ecdsaSign.initSign(privKey);
      ecdsaSign.update(Message.getBytes("UTF-8"));
      byte[] signiert = ecdsaSign.sign();
      signaturBase64 = Base64.getEncoder().encodeToString(signiert);
      return signaturBase64;
    } catch(Exception e) {
      System.out.println(e.getMessage());
    } 
    return "";
  }
  
  public boolean verifizieren(String Message, String publicKeyBase64, String signaturBase64) {
    try {
      KeyFactory kf = KeyFactory.getInstance("EC");
      EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyBase64));
      PublicKey pupKey = kf.generatePublic(publicKeySpec);
      Signature ecdsaVerify = Signature.getInstance("SHA256withECDSA"); 
      ecdsaVerify.initVerify(pupKey);
      ecdsaVerify.update(Message.getBytes("UTF-8"));
      return ecdsaVerify.verify(Base64.getDecoder().decode(signaturBase64));
    } catch(Exception e) {
      System.out.println(e.getMessage());
    } 
    return false;
  }  
  
  public boolean TransaktionAusführen() {
    int p = Transaktion.indexOf("Betrag: ");
    String BetragS = Transaktion.substring(p + 7);
    double Betrag = Double.valueOf(BetragS);
    if (0 < Betrag && Betrag <= Kontostand) {
      Kontostand = Kontostand - Betrag; 
      return true;
    } 
    return false;
  }
  
  public String getEigentümer() {
    return Eigentümer;
  }
  
  public double getKontostand() {
    return Kontostand;
  }

  public String getPublicKeyBase64() {
    return publicKeyBase64;
  }  
  
  public String getTransaktion() {
    return Transaktion;
  }  
  
  public String erstelleTransaktion(String Empfänger, double Betrag) {
    Transaktion =  "Von: " + Eigentümer + " An: " + Empfänger + " Betrag: " + Betrag;
    return Transaktion;
  }  
  
  private void viewKey(String name, Key key) {
    String encoded = Base64.getEncoder().encodeToString(key.getEncoded());
    System.out.println(name + " Key Base64 Encode: " + encoded);
    System.out.println(name + " Key: " + key);
    System.out.println(name + " Key Format: " + key.getFormat());
    System.out.println(name + " Key Algorithm: " + key.getAlgorithm());
    System.out.println(name + " Key Encoded: " );
    showArray(key.getEncoded());
  }   
  
  private void showArray(byte[] b) {
    System.out.println("Länge: " + b.length);
    for (int i = 0; i < b.length; i++) 
      System.out.print(Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1).toUpperCase() + " ");
    System.out.println();
  }

  // Ende Methoden
} // end of Wallet
