IBAN und BIC Validierung

Pecunia non olet

 Titus Flavius Vespasianus

Nach den Beiträgen zu der eher unbekannten Leitweg-ID und den geläufigen Telefonnummern wird sich dieser Beitrag mit den beiden bekanntesten IDs aus dem Zahlungswesen beschäftigen, der IBAN und dem BIC.

Seit der SEPA Einführung werden für Überweisungen und Lastschriften nicht mehr Kontonummer und Bankleitzahl, sondern IBAN und BIC verwendet. SEPA steht für Single Euro Payments Area und standardisiert den Zahlungsverkehr innerhalb der Euro Zone.

Der Bank Identifier Code (BIC) ist ein international standardisierter Code für die eindeutige Identifikation von Banken und die International Bank Account Number (IBAN) ist eine international standardisierte Bankkontonummer.

Da sowohl BIC und IBAN international standardisiert sind, kann ihr Format leicht überprüft werden.

Der BIC besteht aus einem vierstelligen Bankcode, einem zweistelligen Ländercode, einem zweistelligen Code des Ortes und einer optionalen dreistelligen Kennzeichnung der Filiale. So ist die achtstellige BIC der Deutsche Bundesbank Frankfurt am Main etwa MARKDEFF. MARK ist der Bankcode für die Deutsche Bundesbank, DE der Ländercode für Deutschland und FF der Code für Frankfurt. Es gibt auch einen elfstelligen BIC MARKDEFFXXX mit dem Kennzeichen für den Hauptsitz XXX.

Ein Regulärer Ausdruck zum Prüfen eines BIC ist beispielsweise ([A-Z0-9]{4})([A-Z]{2})([A-Z0-9]{2})([A-Z0-9]{3})?. Ein Identifier, der auf diesen Regulären Ausdruck nicht passt, kann schon einmal keine BIC sein.

Die IBAN ist ein wenig länger als der BIC, hat aber einen ähnlich strukturierten Aufbau. Sie startet mit einer zweistelligen Länderkennung, einer zweistelligen Prüfsumme, eine meist achtstelligen Bank-Identifikationsnummer und der Kontonummer. Die Bank-Identifikationsnummer ist in Deutschland die achtstellige Bankleitzahl und die Kontonummer ist in Deutschland maximal 10 Zeichen lang. Daher ist die IBAN in Deutschland 22 Zeichen lang.

Die Erwähnung von Deutschland macht schon einmal klar, die Länge der IBAN ist länderspezifisch, aber maximal 34 Zeichen.

Ein Regulärer Ausdruck zum Prüfen der IBAN ist beispielsweise ([A-Z]{2})([0-9]{2})([A-Z0-9]{11-30}). Die 11 im Ausdruck ergibt sich aus der länge der norwegischen IBAN, sie ist die kürzeste weltweit mit 15 Zeichen.

Mit diesen Informationen kann eine rein syntaktische Validierung implementiert werden.

public class BicValidator implements ConstraintValidator<BIC, String> {

    public static final Pattern PATTERN = Pattern.compile("([A-Z0-9]{4})([A-Z]{2})([A-Z0-9]{2})([A-Z0-9]{3})?");

    @Override
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
        if (value == null) {
            return true;
        }
        Matcher matcher = PATTERN.matcher(value);
        return matcher.matches();
    }
}

Der erste Version des BicValidator prüft den übergebenen String auf null oder eine Übereinstimmung mit dem Pattern. In beiden Fällen ist die Validierung erfolgreich.

public class IbanValidator implements ConstraintValidator<IBAN, String> {

    public static final Pattern PATTERN = Pattern.compile("([A-Z]{2})([0-9]{2})([A-Z0-9]{11,30})");

    @Override
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
        if (value == null) {
            return true;
        }
        Matcher matcher = PATTERN.matcher(value);
        return matcher.matches();
    }
}

Die erste Version des IbanValidator unterscheidet sich nur im verwendeten Pattern und einer anderen Validation-Annotation.

Eine rein syntaktische Validierung ist aber recht langweilig, denn ein String kann sehr leicht wie eine IBAN ausschauen, aber dennoch keine IBAN sein. Der erste Schritt zur Verbesserung ist die Nutzung der Prüfsumme. Die Prüfsumme wird mit dem MOD97-10 Algorithmus berechnet, der auch bei der Leitweg-ID Verwendung findet.

public class IbanValidator implements ConstraintValidator<IBAN, String> {

    public static final Pattern PATTERN = Pattern.compile("([A-Z]{2})([0-9]{2})([A-Z0-9]{11,30})");

    private static final BigInteger VALUE_97 = BigInteger.valueOf(97);

    private static final int[] CHAR_VALUES = charValues();

    private static int[] charValues() {
        String characterValues = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        int[] result = new int['Z' + 1];
        for (int i = 0; i < characterValues.length(); i++) {
            result[characterValues.charAt(i)] = i;
        }
        return result;
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
        if (value == null) {
            return true;
        }
        Matcher matcher = PATTERN.matcher(value);
        if (!matcher.matches()) {
            return false;
        }
        String countryCode = matcher.group(1);
        String basicBankAccountNumber = matcher.group(3);
        int checkDigit = Integer.parseInt(matcher.group(2));

        StringBuilder builder = new StringBuilder(basicBankAccountNumber.length());
        basicBankAccountNumber.chars().mapToObj(c -> CHAR_VALUES[c])
            .map(String::valueOf).forEach(builder::append);
        countryCode.chars().mapToObj(c -> CHAR_VALUES[c])
            .map(String::valueOf).forEach(builder::append);
        return checkDigit == 98 - new BigInteger(builder.append("00").toString()).mod(VALUE_97).intValue()) {
    }
}

Zuerst werden Bankinformationsnummer, Kontonummer und Ländercode und 00 zu einer Zahl zusammengefügt und dann durch 97 geteilt. Das Ergebnis subtrahiert von 98 ergibt die Prüfsumme. Passt das Ergebnis nicht auf die Prüfsumme, dann ist die IBAN nicht valide. Passt die Prüfsumme, dann kann es sich um eine IBAN handeln.

Eine Kleinigkeit muss noch erwähnt werden. Bankinformationsnummer, Kontonummer können Buchstaben enthalten und der Ländercode enthält nur Buchstaben. Daher müssen die Buchstaben ersetzt werden. Der Buchstabe A durch die Zahl 10 bis hin zum Z durch die Zahl 35.

Damit ist die Validierung der IBAN schon recht gut aber im nächsten Beitrag wird die Validierung, insbesondere für deutsche IBAN und BIC, noch weiter verbessert.

Schreibe einen Kommentar