# Symmetrischen "KeyGenerator" schreiben



## Mujahiddin (11. Sep 2012)

Ich steh gerade total auf dem Schlauch!
Ich will eine Funktion schreiben, die mir 16 Zeichen lange Keys generiert (natürlich möglichst zufällig). Das ist ja an sich nicht schwer. Was mich grade richtig zum Nachdenken bringt, ist, dass dies auch symmetrisch sein soll.
Ich soll also 16 Zeichen eingeben können und herausfinden, ob das ein gültiger Key ist.
Allerdings weiß ich überhaupt nicht, wie das gehen könnte. Ich habe nicht mal einen Ansatz.

Und im Internet habe ich bereits nachgeguckt, das ist schon zu 99,99% mit "KeyGenerator für App" zugemüllt.

mit Hashes kann ich leider nicht arbeiten.
Ich habe nur "ansatzweise" eine "Idee" gehabt, aber bei Weitem kein zufriedenstellendes Ergebnis:


```
private static final String PREFIX = "XyZz";

public static String generateKey() {
	String s = randomString();
	String base64 = DatatypeConverter.printBase64Binary( s.getBytes() );
	byte[] b = base64.getBytes();
	String key = new BigInteger( 1, b ).toString( 16 );
	return key;
}

public static boolean valid(String key) {
	byte[] b = new BigInteger( key, 16 ).toByteArray();
	System.out.println( Arrays.toString( b ) );
	String orig = new String( b );
	orig = new String( DatatypeConverter.parseBase64Binary( orig ) );
	return orig.startsWith( PREFIX );
}

public static String randomString() {
	String ret = PREFIX;
	ret += (char) ( Math.random() * 94 + 32 );
	ret += (char) ( Math.random() * 94 + 32 );
	return ret;
}
```

Das Problem ist, dass jeder generierte Key mit "57486c61656" anfängt.
Außerdem gibt es hierbei nur 94*94 Variationen, die Variationen sollen aber mindestems im Milliardenbereich liegen.

Hat irgendjemand eine Idee oder kann mich auf eine Seite verweisen?


----------



## sMau90 (12. Sep 2012)

Ich bin mir nicht so ganz sicher, ob ich dich richtig verstanden hab, aber du willst eine Art "CD-Key" Verhalten oder? Also du gibst einen Key ein, dein Programm kann entscheiden ob er gültig ist, wobei du gleichzeitig in der Lage bist, möglichst zufällig solche Keys zu generieren.
Falls ich es richtig verstanden habe könnten diese Seiten evtl. interessant sein:
Venish Joe - Serial Key Generation and Validation in Java
java - Serial keys: What to do? - Stack Overflow
Serial Generator And Validator - Java | Dream.In.Code

Guck dir evtl. auch mal den KeyGenerator von Java an, der kann recht viel evtl. findest du dort etwas was du verwenden kannst.
Alles komplett selbst zu machen, ohne ein bestehendes Kryptosystem zu nutzen geht natürlich auch, wird aber bedeutend mehr Arbeit.

Grüße,
sMau


----------



## kay73 (13. Sep 2012)

Das Problem bei den vorgestellten Ansätzen ist, dass der Code zum Generieren ausgeliefert wird und damit der "KeyGen" zum Ausstellen von gültigen aber gefälschten Schlüsseln frei Haus kommt.

Anders ist das, wenn ein asymmetrisches Verfahren wie RSA verwendet wird und das ist definitiv machbar. Wir hatten vor einiger Zeit diesen Thread in dem das Thema breitgetreten wurde. 

Demoutput:
	
	
	
	





```
Ein Schlüsselpaar...
private:22940117733726891
public:34410176972520049

Ein paar Seriennummern...
2EPAFVX3X1XIA0AJ (ok)
44Z12Z30MODMV12K (ok)
34N5N1ABNT80LCLL (ok)
3M3M0HWI52BRJURE (ok)
3YHGL1YW83Y5SYZJ (ok)
32AD7VMG50YFV786 (ok)
3SC0ADIUITS5B9VY (ok)
2APGCBIBZAX9T3W0 (ok)
3R7LOT34CF0LQ6F6 (ok)
2F4LMJT7HISQ80HE (ok)
```

Hier ist der Code, abgestellt auf die gewünschte Länge von 16 Zeichen. 

Die Funktion 
	
	
	
	





```
genKeyPair()
```
 darf natürlich nur ein einziges Mal ausgeführt werden und das Schlüsselpaar wird notiert.
Der _privateKey_ bleibt geheim; der _publicKey_ wird hart ins Produkt kodiert.
Nur die 
	
	
	
	





```
verify()
```
-Einzeiler kommen in das ausgelieferte Produkt. 


```
import java.math.BigInteger;
import java.util.Random;

public class StupidRSA {

    private static final BigInteger E = BigInteger.valueOf(3L);

    final Random r = new Random();
    
    public static class KeyPair {

        public final BigInteger publicKey;
        public final BigInteger privateKey;

        public KeyPair(final BigInteger n, final BigInteger d) {
            this.publicKey = n;
            this.privateKey = d;
        }
    }

    public KeyPair genKeyPair() {

        int nTries = 0;
        do {
            try {
                boolean hasPrime = false;

                BigInteger p = BigInteger.ZERO;
                while (!hasPrime) {
                    p = BigInteger.probablePrime(28, r);
                    hasPrime = p.isProbablePrime(8);
                }

                hasPrime = false;
                BigInteger q = BigInteger.ZERO;
                while (!hasPrime) {
                    q = BigInteger.probablePrime(28, r);
                    hasPrime = p.isProbablePrime(8) && !(q.equals(p));
                }

                final BigInteger n = p.multiply(q);

                final BigInteger eTot = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
                final BigInteger d = E.modInverse(eTot);

                return new KeyPair(n, d);
            } catch (final ArithmeticException ex) {
            }
        } while (nTries++ < 20);

        throw new RuntimeException("Konnte kein Schluesselpaar erzeugen.");
    }

    public BigInteger hash(final BigInteger number) {
        return number.mod(BigInteger.valueOf(8379));
    }

    public BigInteger sign(final BigInteger number, final KeyPair kp) {
        return hash(number).modPow(kp.privateKey, kp.publicKey);
    }

    public boolean verify(final BigInteger message, final BigInteger signature, final BigInteger publicKey) {
        return hash(message).equals(signature.modPow(E, publicKey));
    }

    public String generateSerial(final KeyPair kp, final Random r) {
        int nTries = 0;
        do {
            final BigInteger message = BigInteger.probablePrime(28, r);
            if (message.toString(36).length() != 6) {
                continue;
            }

            final BigInteger sign = sign(message, kp);
            if (sign.toString(36).length() != 10) {
                continue;
            }

            return (message.toString(36) + sign.toString(36)).toUpperCase();
        } while (nTries++ < 100);

        throw new RuntimeException("Konnte keine Seriennnummer generieren");
    }

    public boolean verify(final String serial, final BigInteger publicKey) {
        return verify(new BigInteger(serial.substring(0, 6), 36), new BigInteger(serial.substring(6, 16), 36), publicKey);
    }

    public static void main(String[] args) {

        final StupidRSA s = new StupidRSA();

        final KeyPair kp = s.genKeyPair();
        System.out.println(String.format("Ein Schlüsselpaar...\n%1$s:%2$s\n%3$s:%4$s", "private", kp.privateKey, "public", kp.publicKey));

        final Random r = new Random();

        System.out.println("\nEin paar Seriennummern...");
        for (int i = 0; i < 10; i++) {
            final String serial = s.generateSerial(kp, r);
            System.out.println(serial + (s.verify(serial, kp.publicKey) ? " (ok)" : " NOK!"));
        }
    }
}
```


----------

