Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs

Deutsche Personalausweisnummern verifizieren

Geschrieben von: Christoph Wille
Kategorie: C#

This printed page brought to you by AlphaSierraPapa

Im Internet findet man immer wieder interessante Ansätze, die Identität bzw. das Alter der Surfer zu bestimmen. Einer davon ist die Personalausweisnummer vom Surfer eintippen zu lassen, da diese neben allgemeinen Angaben auch das Alter beinhaltet. Mit Hilfe von in der Personalausweisnummer eingebauten Prüfziffern kann man kontrollieren, ob die Eingaben korrekt sind.

Sicherheitshinweis Nicht nur wir können die Prüfziffern verifizieren, sondern die "Gegenseite" kann da der Algorithmus bekannt ist, sich gültige Personalausweisnummern generieren lassen. Ein Beispiel dazu ist auf der Seite Berechnung der Personalausweis-Nummern inklusive Prüziffern zu finden.

Wie sieht nun eine Personalausweisnummer aus? Im Newsarchiv von Google findet sich ein Posting, aus dem diese Aufschlüsselung herauskopiert ist:

731731731    731731  731731
*********    ******  ******
wwwwNNNNNaD<<yyMMddb<YYmmDDc<<<<<<d
|||||||||||  ||||||| |||||||      |
|||||||||||  ||||||| |||||||      -\__ Pruefsumme ALLER Ziffern
|||||||||||  ||||||| |||||||
|||||||||||  ||||||| ||||||-\__ Pruefsumme Ablaufdatum
|||||||||||  ||||||| ||||--\__ Ablaufdatum Tag
|||||||||||  ||||||| ||--\__ Ablaufdatum Monat
|||||||||||  ||||||| --\__ Ablaufdatum Jahr
|||||||||||  |||||||
|||||||||||  ||||||-\__ Pruefsumme Geb.-Datum
|||||||||||  ||||--\__ Geb.-Tag
|||||||||||  ||--\__ Geb.-Monat
|||||||||||  --\__ Geb.-Jahr
|||||||||||
|||||||||| \__ Staatszugehoerigkeit D = Deutsch ?
||||||||| \__ Pruefsumme fuer wwwwNNNNN
||||-----\__ laufende Zaehlnummer
----_ Erstwohnsitz Kennzahl

Wie man sieht, gibt es vier Prüfziffern a, b, c und d. Die erste Prüfziffer, a, wird über die Kennzahl des Erstwohnsitzes und eine fortlaufende Ausweisnummer errechnet. Die zweite über das Geburtsdatum, und die dritte über das Ablaufdatum. Die Prüfziffer d ist etwas spezieller: diese wird nach Errechnung von a, b und c über alle Ziffern errechnet (also mit den drei Prüfziffern inkludiert, damit man die Prüfziffern prüfen kann).

Details über den Algorithmus finden sich im Posting beziehungsweise sehr detailliert aufgeschlüsselt im Artikel Prüfziffern: Deutscher Personalausweis.

Die Kurzform des Algorithmus zur Prüfziffernberechnung: Man nimmt die erste Zahl, und multipliziert sie mit 7. Dazu addiert man die zweite Zahl, die zuvor mit 3 multipliziert wird. Die dritte wird einfach dazuaddiert (mit 1 multipliziert). Hat man mehr als drei Zahlen, beginnt man bei der vierten Zahl wieder mit 7 zu multiplizieren (und so weiter). Von der so errechneten Prüfsumme nimmt man die Einerstelle, und schon ist die Prüfziffer fertig. Wie einfach das ist, wird jeder im Code sehen.

Die Klasse Personalausweisnummer

Um die Wiederverwendung in allen Programmiersprachen zu erleichtern, habe ich die Klasse Personalausweisnummer in eine eigene Datei namens PersoClass.cs ausgelagert. Das erlaubt das direkte Einbinden in C# Projekte, beziehungsweise das Kompilieren als eigenständige Assembly, die dann auch in zB VB.NET ASP.NET Projekten eingebunden werden kann.

Die Klasse besitzt folgende Eigenschaften und Methoden:

public class Personalausweisnummer
{
  public Personalausweisnummer();
  
  public string ErstwohnsitzKennzahl {
    set;
  }
  
  public string Zaehlnummer {
    set;
  }  

  public string Geburtsdatum {
    set;
  }  
  
  public string Ablaufdatum {
    set;
  }

  public bool IsDataValid();

  public bool PruefsummenBerechnung(out byte PruefsummeAZiffer, out byte PruefsummeBZiffer, 
                                    out byte PruefsummeCZiffer, out byte PruefsummeDZiffer);
}

Die Eigenschaften sind alle nur mit einem set Accessor ausgestattet, das heißt, man kann die Eigenschaften nur setzen, nicht aber lesen. Die Methode IsDataValid wird von der Methode PruefsummenBerechnung aufgerufen, bevor die vier Prüfziffern berechnet werden - damit stelle ich sicher, daß alle vier Eigenschaften korrekt gesetzt wurden.

Die Eigenschaften

Die vier Properties der Klasse Personalausweisnummer nehmen jeweils einen String als Input an. Diese Strings werden in den set Accessors in die Einzelziffern umgewandelt, und diese in Arrays gespeichert:

public class Personalausweisnummer
{
  private int[] abErstwohnsitzKennzahl;
  private int[] abZaehlnummer;
  private int[] abGeburtsdatum;
  private int[] abAblaufdatum;
  private int ValidData;
  
  public Personalausweisnummer()
  {
    abErstwohnsitzKennzahl = new int[4];
    abZaehlnummer = new int[5];
    abGeburtsdatum = new int[6];
    abAblaufdatum = new int[6];
    ValidData = 0;
  }

Die Arrays sind 4, 5 beziehungsweise zweimal 6 Elemente groß. Die Arrays werden im Konstruktor initialisiert, ebenso wie die Membervariable ValidData, die wir zum Mitführen der Gültigkeit der vier Arrays verwenden. Diese Variable wird jeweils in den set Accessor gesetzt; sehen wir uns den ErstwohnsitzKennzahl Accessor exemplarisch an:

  public string ErstwohnsitzKennzahl {
    set {
      ValidData &= ~((int)Persodaten.ErstwohnsitzKennzahl);
      if (value.Length != 4) {
        throw new ArgumentException("Erstwohnsitz Kennzahl muß 4 Ziffern lang sein");
      }
      try {
        for (int i=0; i <= 3; i++) {
          abErstwohnsitzKennzahl[i] = Int32.Parse(value[i].ToString());
        }
      }
      catch(Exception e) {
        throw e;
      }
      ValidData |= ((int)Persodaten.ErstwohnsitzKennzahl);
    }
  }

Bei Persodaten, die bei der Zuweisung von ValidData verwendet wird, handelt es sich um eine Enumeration:

public enum Persodaten {
  ErstwohnsitzKennzahl = 1,
  Zaehlnummer = 2,
  Geburtsdatum = 4,
  Ablaufdatum = 8
}

Damit habe ich den Trick auch schon verraten, wie man die Gültigkeit von vier Variablen in einer einzigen speichert: mit bitweisen Operationen. Am Anfang des Accessors wird die Variable auf ungültig gesetzt (Und-en mit dem Komplementär), und falls kein Fehler aufgetreten ist, wird am Ende des Accessors geodert. Fehlerfälle sind inkorrekte Stringlängen und Nicht-Ziffern in den Strings, auf weitere Überprüfungen habe ich verzichtet.

IsDataValid - Kontrolle vor der Berechnung

Bevor PruefsummenBerechnung mit der Berechnung startet, ruft diese die Methode IsDataValid auf. Und diese vergleicht die Membervariable ValidData mit den geoderten Enumerationmembers (es sind nur dann alle Bits gesetzt, wenn alle Daten korrekt waren):

  public bool IsDataValid()
  {
    int nValidIf = ((int)Persodaten.ErstwohnsitzKennzahl) | ((int)Persodaten.Zaehlnummer) |
      ((int)Persodaten.Geburtsdatum) | ((int)Persodaten.Ablaufdatum);
    
    return (nValidIf == ValidData);
  }

Nach diesem Check kann die Prüfziffernberechnung starten.

Prüfziffernberechnung

Beginnen wir in der Methode PruefsummenBerechnung ganz oben:

  public bool PruefsummenBerechnung(out byte PruefsummeAZiffer, out byte PruefsummeBZiffer, 
                                    out byte PruefsummeCZiffer, out byte PruefsummeDZiffer)
  {
    PruefsummeAZiffer = PruefsummeBZiffer = PruefsummeCZiffer = PruefsummeDZiffer = 0;
    if (!IsDataValid()) return false;

Die out Variablen müssen initialisiert werden, damit falls IsDataValid ein false liefert, diese Variablen auf gültige Werte gesetzt sind (uninitialisierte out Variablen dürfen niemals die Methode verlassen). Nach diesem ersten (und einzigen) Check wird auch schon die Prüfziffer a berechnet:

    int PruefsummeA;
    PruefsummeA = (abErstwohnsitzKennzahl[0] * 7) +
      (abErstwohnsitzKennzahl[1] * 3) +
      (abErstwohnsitzKennzahl[2]* 1) +
      (abErstwohnsitzKennzahl[3] * 7) +
      (abZaehlnummer[0] * 3) +
      (abZaehlnummer[1] * 1) +
      (abZaehlnummer[2] * 7) +
      (abZaehlnummer[3] * 3) +
      (abZaehlnummer[4] * 1);
    string strPruefsummeA = Convert.ToString(PruefsummeA);
    PruefsummeAZiffer = Convert.ToByte(strPruefsummeA.Substring(strPruefsummeA.Length - 1));

Hier sieht man den Algorithmus bei der Arbeit, und er ist tatsächlich nicht schwer zu verstehen. Die letzten beiden Zeilen erledigen das Ermitteln der Einerstelle - diese wird dann auf die erste out Variable zugewiesen.

Die Berechnung für b und c läuft ident, interessant ist wieder d, damit man sieht, wie die anderen Prüfziffern in die Berechnung einfliessen:

    int PruefsummeD;
    PruefsummeD = (abErstwohnsitzKennzahl[0] * 7) +
      (abErstwohnsitzKennzahl[1] * 3) +
      (abErstwohnsitzKennzahl[2]* 1) +
      (abErstwohnsitzKennzahl[3] * 7) +
      (abZaehlnummer[0] * 3) +
      (abZaehlnummer[1] * 1) +
      (abZaehlnummer[2] * 7) +
      (abZaehlnummer[3] * 3) +
      (abZaehlnummer[4] * 1) +
      (PruefsummeAZiffer * 7) +
      (abGeburtsdatum[0] * 3) +
      (abGeburtsdatum[1] * 1) +
      (abGeburtsdatum[2] * 7) +
      (abGeburtsdatum[3] * 3) +
      (abGeburtsdatum[4] * 1) +
      (abGeburtsdatum[5] * 7) + 
      (PruefsummeBZiffer * 3) +
      (abAblaufdatum[0] * 1) +
      (abAblaufdatum[1] * 7) +
      (abAblaufdatum[2] * 3) +
      (abAblaufdatum[3] * 1) +
      (abAblaufdatum[4] * 7) +
      (abAblaufdatum[5] * 3) +
      (PruefsummeCZiffer * 1);
    string strPruefsummeD = Convert.ToString(PruefsummeD);
    PruefsummeDZiffer = Convert.ToByte(strPruefsummeD.Substring(strPruefsummeD.Length - 1));

Der Algorithmus wird einfach auf alle Zahlen in ihrer Reihenfolge angewendet. Und damit haben wir alle vier Prüfziffern, und die Methode beendet mit true.

Verwendung der Klasse Personalausweisnummer

Im Download mit dabei ist eine kleine Kommandozeilenanwendung, die die Verwendung anhand eines Datensatzes demonstriert:

class MainClass
{
  public static void Main(string[] args)
  {
    Personalausweisnummer perso = new Personalausweisnummer();
    try {
      perso.ErstwohnsitzKennzahl = "1000";  // vierstellig
      perso.Zaehlnummer = "10000";  // fünfstellig
      perso.Geburtsdatum = "730729";  // Jahr, Monat, Tag
      perso.Ablaufdatum = "050101";  // Jahr, Monat Tag
    }
    catch(Exception e) {
      Console.WriteLine("Daten inkorrekt: ");
      Console.WriteLine(e.Message);
    }
    
    byte a, b, c, d;
    bool bOk = perso.PruefsummenBerechnung(out a, out b, out c, out d);
    if (bOk) {
      Console.WriteLine("a: {0} b: {1} c: {2} d: {3}",a, b, c, d);
    }
    else {
      Console.WriteLine("Berechnung der Prüfsummen konnte nicht durchgeführt werden.");
    }
    
  }
}

Bei den vier Eigenschaften können Exceptions auftreten, daher ist der Zuweisungsblock in try...catch eingebettet. Danach wird die Methode PruefsummenBerechnung aufgerufen, und die Resultate an die Console ausgegeben.

Wer die Klasse in ASP.NET oder anderen Programmiersprachen als C# verwenden will, kann die Batch-Datei builddll.bat aufrufen - damit erhält man eine Assembly, die beliebig weiterverwendet werden kann.

Schlußbemerkung

Falls man die Personalausweisnummer zur Verifizierung des Alters einsetzt, sollte man sich immer bewußt sein, daß jeder eine "gültige" Nummer errechnen kann. Fälschungssicher - ohne die physische Karte in Händen zu halten - ist die Personalausweisnummer nicht.

This printed page brought to you by AlphaSierraPapa

Download des Codes

Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20020507.zip

Verwandte Artikel

Datentypen in C#
http:/www.aspheute.com/artikel/20000726.htm
Die String Klasse in C#
http:/www.aspheute.com/artikel/20000803.htm
Enums lesbar machen
http:/www.aspheute.com/artikel/20010215.htm
Exception Handling in C#
http:/www.aspheute.com/artikel/20000724.htm
Kontrollstatements in C#
http:/www.aspheute.com/artikel/20000714.htm
Schleifenbefehle in C#
http:/www.aspheute.com/artikel/20000717.htm
Sprachenintegration in .NET
http:/www.aspheute.com/artikel/20011010.htm
Verwendung von Arrays in C#
http:/www.aspheute.com/artikel/20000731.htm

Links zu anderen Sites

#develop
http://www.icsharpcode.net/opensource/sd/
Berechnung der Personalausweis-Nummern inklusive Prüziffern
http://365-24-7.net/perso/
perso - Berechnung der Personalausweis-Nummern
http://www.sylence.de/perso/
Prüfziffern: Deutscher Personalausweis
http://www.pruefziffernberechnung.de/P/Personalausweis-DE.shtml
Subject: Algorithmus Personalausweisnummer (was Re: Jugendschutz im WWW)
http://groups.google.com/groups?selm=8ns4ll%24c2t%2413%241%40news.t-online.com&output=gplain

 

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.