OpenWebNet password

From Rosetta Code
Revision as of 13:06, 7 June 2018 by Thundergnat (talk | contribs) (move swift to correct place)

Calculate the password requested by ethernet gateways from the Legrand / Bticino MyHome OpenWebNet home automation system when the user's ip address is not in the gateway's whitelist

Note: Factory default password is '12345'. Changing it is highly recommended !

conversation goes as follows

← *#*1##
→ *99*0##
← *#603356072##

at which point a password should be sent back, calculated from the "password open" that is set in the gateway, and the nonce that was just sent

→ *#25280520##
← *#*1##

D

Translation of: Python

<lang d>import std.stdio, std.string, std.conv, std.ascii, std.algorithm;

ulong ownCalcPass(in ulong password, in string nonce) pure nothrow @safe @nogc in {

   assert(nonce.representation.all!isDigit);

} body {

   enum ulong m_1        = 0x_FFFF_FFFF_UL;
   enum ulong m_8        = 0x_FFFF_FFF8_UL;
   enum ulong m_16       = 0x_FFFF_FFF0_UL;
   enum ulong m_128      = 0x_FFFF_FF80_UL;
   enum ulong m_16777216 = 0X_FF00_0000_UL;
   auto flag = true;
   ulong num1 = 0, num2 = 0;
   foreach (immutable char c; nonce) {
       num1 &= m_1;
       num2 &= m_1;
       switch (c) {
           case '0':
               num1 = num2;
               break;
           case '1':
               if (flag)
                   num2 = password;
               flag = false;
               num1 = num2 & m_128;
               num1 = num1 >> 7;
               num2 = num2 << 25;
               num1 = num1 + num2;
               break;
           case '2':
               if (flag)
                   num2 = password;
               flag = false;
               num1 = num2 & m_16;
               num1 = num1 >> 4;
               num2 = num2 << 28;
               num1 = num1 + num2;
               break;
           case '3':
               if (flag)
                   num2 = password;
               flag = false;
               num1 = num2 & m_8;
               num1 = num1 >> 3;
               num2 = num2 << 29;
               num1 = num1 + num2;
               break;
           case '4':
               if (flag)
                   num2 = password;
               flag = false;
               num1 = num2 << 1;
               num2 = num2 >> 31;
               num1 = num1 + num2;
               break;
           case '5':
               if (flag)
                   num2 = password;
               flag = false;
               num1 = num2 << 5;
               num2 = num2 >> 27;
               num1 = num1 + num2;
               break;
           case '6':
               if (flag)
                   num2 = password;
               flag = false;
               num1 = num2 << 12;
               num2 = num2 >> 20;
               num1 = num1 + num2;
               break;
           case '7':
               if (flag)
                   num2 = password;
               flag = false;
               num1 = num2 & 0xFF00UL;
               num1 = num1 + ((num2 & 0xFFUL) << 24);
               num1 = num1 + ((num2 & 0xFF0000UL) >> 16);
               num2 = (num2 & m_16777216) >> 8;
               num1 = num1 + num2;
               break;
           case '8':
               if (flag)
                   num2 = password;
               flag = false;
               num1 = num2 & 0xFFFFUL;
               num1 = num1 << 16;
               num1 = num1 + (num2 >> 24);
               num2 = num2 & 0xFF0000UL;
               num2 = num2 >> 8;
               num1 = num1 + num2;
               break;
           case '9':
               if (flag)
                   num2 = password;
               flag = false;
               num1 = ~num2;
               break;
           default: // Impossible if contracts are active.
               assert(0, "Non-digit in nonce");
       }
       num2 = num1;
   }
   return num1 & m_1;

}

void ownTestCalcPass(in string sPassword, in string nonce, in ulong expected) in {

   assert(sPassword.representation.all!isDigit);
   assert(nonce.representation.all!isDigit);

} body {

   immutable password = sPassword.to!ulong;
   immutable res = ownCalcPass(password, nonce);
   immutable m = format("%d %s %d %d", password, nonce, res, expected);
   writeln((res == expected) ? "PASS " : "FAIL ", m);

}

void main() {

   ownTestCalcPass("12345", "603356072", 25280520UL);
   ownTestCalcPass("12345", "410501656", 119537670UL);

}</lang>

Output:
PASS 12345 603356072 25280520 25280520
PASS 12345 410501656 119537670 119537670

JavaScript

<lang javascript> function calcPass (pass, nonce) { var flag = true; var num1 = 0x0; var num2 = 0x0; var password = parseInt(pass, 10);

for (var c in nonce) { c = nonce[c]; if (c!='0') { if (flag) num2 = password; flag = false; } switch (c) { case '1': num1 = num2 & 0xFFFFFF80; num1 = num1 >>> 7; num2 = num2 << 25; num1 = num1 + num2; break; case '2': num1 = num2 & 0xFFFFFFF0; num1 = num1 >>> 4; num2 = num2 << 28; num1 = num1 + num2; break; case '3': num1 = num2 & 0xFFFFFFF8; num1 = num1 >>> 3; num2 = num2 << 29; num1 = num1 + num2; break; case '4': num1 = num2 << 1; num2 = num2 >>> 31; num1 = num1 + num2; break; case '5': num1 = num2 << 5; num2 = num2 >>> 27; num1 = num1 + num2; break; case '6': num1 = num2 << 12; num2 = num2 >>> 20; num1 = num1 + num2; break; case '7': num1 = num2 & 0x0000FF00; num1 = num1 + (( num2 & 0x000000FF ) << 24 ); num1 = num1 + (( num2 & 0x00FF0000 ) >>> 16 ); num2 = ( num2 & 0xFF000000 ) >>> 8; num1 = num1 + num2; break; case '8': num1 = num2 & 0x0000FFFF; num1 = num1 << 16; num1 = num1 + ( num2 >>> 24 ); num2 = num2 & 0x00FF0000; num2 = num2 >>> 8; num1 = num1 + num2; break; case '9': num1 = ~num2; break; case '0': num1 = num2; break; } num2 = num1; } return (num1 >>> 0).toString(); }

exports.calcPass = calcPass;

console.log ('openpass initialization'); function testCalcPass (pass, nonce, expected) { var res = calcPass (pass, nonce); var m = pass + ' ' + nonce + ' ' + res + ' ' + expected; if (res == parseInt(expected, 10)) console.log ('PASS '+m); else console.log ('FAIL '+m); }

testCalcPass ('12345', '603356072', '25280520'); testCalcPass ('12345', '410501656', '119537670'); testCalcPass ('12345', '630292165', '4269684735'); testCalcPass ('12345', '523781130', '537331200'); </lang>

Kotlin

Translation of: Python

<lang scala>// version 1.1.51

fun ownCalcPass(password: Long, nonce: String): Long {

   val m1        = 0xFFFF_FFFFL
   val m8        = 0xFFFF_FFF8L
   val m16       = 0xFFFF_FFF0L
   val m128      = 0xFFFF_FF80L
   val m16777216 = 0xFF00_0000L
   var flag = true
   var num1 = 0L
   var num2 = 0L
   for (c in nonce) {
       num2 = num2 and m1
       when (c) {
           '1' -> {
               if (flag) num2 = password
               flag = false
               num1 = num2 and m128
               num1 = num1 ushr 7
               num2 = num2 shl 25
               num1 = num1 + num2
           }
           '2' -> {
               if (flag) num2 = password
               flag = false
               num1 = num2 and m16
               num1 = num1 ushr 4
               num2 = num2 shl 28
               num1 = num1 + num2
           }
           '3' -> {
               if (flag) num2 = password
               flag = false
               num1 = num2 and m8
               num1 = num1 ushr 3
               num2 = num2 shl 29
               num1 = num1 + num2
           }
           '4' -> {
               if (flag) num2 = password
               flag = false
               num1 = num2 shl 1
               num2 = num2 ushr 31
               num1 = num1 + num2
           }
           '5' -> {
               if (flag) num2 = password
               flag = false
               num1 = num2 shl 5
               num2 = num2 ushr 27
               num1 = num1 + num2
           }
           '6' -> {
               if (flag) num2 = password
               flag = false
               num1 = num2 shl 12
               num2 = num2 ushr 20
               num1 = num1 + num2
           }
           '7' -> {
               if (flag) num2 = password
               flag = false
               num1 = num2 and 0xFF00L
               num1 = num1 + ((num2 and 0xFFL) shl 24)
               num1 = num1 + ((num2 and 0xFF0000L) ushr 16)
               num2 = (num2 and m16777216) ushr 8
               num1 = num1 + num2
           }
           '8' -> {
               if (flag) num2 = password
               flag = false
               num1 = num2 and 0xFFFFL
               num1 = num1 shl 16
               num1 = num1 + (num2 ushr 24)
               num2 = num2 and 0xFF0000L
               num2 = num2 ushr 8
               num1 = num1 + num2
           }
           '9' -> {
               if (flag) num2 = password
               flag = false
               num1 = num2.inv()
           }
           else -> num1 = num2
       }
       num2 = num1
   }
   return num1 and m1

}

fun ownTestCalcPass(passwd: String, nonce: String, expected: Long) {

   val res = ownCalcPass(passwd.toLong(), nonce)
   val m = "$passwd  $nonce  $res  $expected"
   println(if (res == expected) "PASS  $m" else "FAIL  $m")

}

fun main(args: Array<String>) {

   ownTestCalcPass("12345", "603356072", 25280520)
   ownTestCalcPass("12345", "410501656", 119537670)

}</lang>

Output:
PASS  12345  603356072  25280520  25280520
PASS  12345  410501656  119537670  119537670

Python

<lang python> def ownCalcPass (password, nonce, test=False) :

   start = True    
   num1 = 0
   num2 = 0
   password = int(password)
   if test:
       print("password: %08x" % (password))
   for c in nonce :
       if c != "0":
           if start:
               num2 = password
           start = False
       if test:
           print("c: %s num1: %08x num2: %08x" % (c, num1, num2))
       if c == '1':
           num1 = (num2 & 0xFFFFFF80) >> 7
           num2 = num2 << 25
       elif c == '2':
           num1 = (num2 & 0xFFFFFFF0) >> 4
           num2 = num2 << 28
       elif c == '3':
           num1 = (num2 & 0xFFFFFFF8) >> 3
           num2 = num2 << 29
       elif c == '4':
           num1 = num2 << 1
           num2 = num2 >> 31
       elif c == '5':
           num1 = num2 << 5
           num2 = num2 >> 27
       elif c == '6':
           num1 = num2 << 12
           num2 = num2 >> 20
       elif c == '7':
           num1 = num2 & 0x0000FF00 | (( num2 & 0x000000FF ) << 24 ) | (( num2 & 0x00FF0000 ) >> 16 )
           num2 = ( num2 & 0xFF000000 ) >> 8
       elif c == '8':
           num1 = (num2 & 0x0000FFFF) << 16 | ( num2 >> 24 )
           num2 = (num2 & 0x00FF0000) >> 8
       elif c == '9':
           num1 = ~num2
       else :
           num1 = num2
       num1 &= 0xFFFFFFFF
       num2 &= 0xFFFFFFFF
       if (c not in "09"):
           num1 |= num2
       if test:
           print("     num1: %08x num2: %08x" % (num1, num2))
       num2 = num1
   return num1

def test_passwd_calc(passwd, nonce, expected):

   res = ownCalcPass(passwd, nonce, False)
   m = passwd+' '+nonce+' '+str(res)+' '+str(expected)
   if res == int(expected) :
       print('PASS '+m)
   else :
       print('FAIL '+m)

if __name__ == '__main__':

   test_passwd_calc('12345','603356072','25280520')
   test_passwd_calc('12345','410501656','119537670')
   test_passwd_calc('12345','630292165','4269684735')

</lang>

PHP

<lang PHP>function ownCalcPass($password, $nonce) {

   $msr = 0x7FFFFFFF;
   $m_1 = (int)0xFFFFFFFF;
   $m_8 = (int)0xFFFFFFF8;
   $m_16 = (int)0xFFFFFFF0;
   $m_128 = (int)0xFFFFFF80;
   $m_16777216 = (int)0xFF000000;
   $flag = True;
   $num1 = 0;
   $num2 = 0;
   foreach (str_split($nonce) as $c) {
       $num1 = $num1 & $m_1;
       $num2 = $num2 & $m_1;
       if ($c == '1') {
           $length = !$flag;
           if (!$length) {
               $num2 = $password;
           }
           $num1 = $num2 & $m_128;
           $num1 = $num1 >> 1;
           $num1 = $num1 & $msr;
           $num1 = $num1 >> 6;
           $num2 = $num2 << 25;
           $num1 = $num1 + $num2;
           $flag = False;
       } elseif ($c == '2') {
           $length = !$flag;
           if (!$length) {
               $num2 = $password;
           }
           $num1 = $num2 & $m_16;
           $num1 = $num1 >> 1;
           $num1 = $num1 & $msr;
           $num1 = $num1 >> 3;
           $num2 = $num2 << 28;
           $num1 = $num1 + $num2;
           $flag = False;
       } elseif ($c == '3') {
           $length = !$flag;
           if (!$length) {
               $num2 = $password;
           }
           $num1 = $num2 & $m_8;
           $num1 = $num1 >> 1;
           $num1 = $num1 & $msr;
           $num1 = $num1 >> 2;
           $num2 = $num2 << 29;
           $num1 = $num1 + $num2;
           $flag = False;
       } elseif ($c == '4') {
           $length = !$flag;
           if (!$length) {
               $num2 = $password;
           }
           $num1 = $num2 << 1;
           $num2 = $num2 >> 1;
           $num2 = $num2 & $msr;
           $num2 = $num2 >> 30;
           $num1 = $num1 + $num2;
           $flag = False;
       } elseif ($c == '5') {
           $length = !$flag;
           if (!$length) {
               $num2 = $password;
           }
           $num1 = $num2 << 5;
           $num2 = $num2 >> 1;
           $num2 = $num2 & $msr;
           $num2 = $num2 >> 26;
           $num1 = $num1 + $num2;
           $flag = False;
       } elseif ($c == '6') {
           $length = !$flag;
           if (!$length) {
               $num2 = $password;
           }
           $num1 = $num2 << 12;
           $num2 = $num2 >> 1;
           $num2 = $num2 & $msr;
           $num2 = $num2 >> 19;
           $num1 = $num1 + $num2;
           $flag = False;
       } elseif ($c == '7') {
           $length = !$flag;
           if (!$length) {
               $num2 = $password;
           }
           $num1 = $num2 & 0xFF00;
           $num1 = $num1 + (( $num2 & 0xFF ) << 24 );
           $num1 = $num1 + (( $num2 & 0xFF0000 ) >> 16 );
           $num2 = $num2 & $m_16777216;
           $num2 = $num2 >> 1;
           $num2 = $num2 & $msr;
           $num2 = $num2 >> 7;
           $num1 = $num1 + $num2;
           $flag = False;
       } elseif ($c == '8') {
           $length = !$flag;
           if (!$length) {
               $num2 = $password;
           }
           $num1 = $num2 & 0xFFFF;
           $num1 = $num1 << 16;
           $numx = $num2 >> 1;
           $numx = $numx & $msr;
           $numx = $numx >> 23;
           $num1 = $num1 + $numx;
           $num2 = $num2 & 0xFF0000;
           $num2 = $num2 >> 1;
           $num2 = $num2 & $msr;
           $num2 = $num2 >> 7;
           $num1 = $num1 + $num2;
           $flag = False;
       } elseif ($c == '9') {
           $length = !$flag;
           if (!$length) {
               $num2 = $password;
           }
           $num1 = ~(int)$num2;
           $flag = False;
       } else {
           $num1 = $num2;
       }
       $num2 = $num1;
   }
   return sprintf('%u', $num1 & $m_1);

} </lang>

Racket

Translation of: Python

(followed by some aggressive refactoring)

<lang racket>#lang racket/base (define (32-bit-truncate n)

 (bitwise-and n #xFFFFFFFF))

(define (own-calc-pass password-string nonce)

 (define-values (num-1 flag)
   (for/fold ((num-1 0) (flag #t))
             ((c (in-string nonce)))
     (let* ((num-1 (32-bit-truncate num-1))
            (num-2 (if flag (string->number password-string) num-1)))
       
       (define (and-right-left-add mask right left)
         (values (+ (arithmetic-shift (bitwise-and num-2 mask) (- right))
                    (arithmetic-shift num-2 left))
                 #f))
       (define (left-right-add left right)
         (values (+ (arithmetic-shift num-2 left) (arithmetic-shift num-2 (- right))) #f))
       (define (stage-7)
         (values (+ (+ (+ (bitwise-and num-2 #xff00)
                          (arithmetic-shift (bitwise-and num-2 #xff) 24))
                       (arithmetic-shift (bitwise-and num-2 #xff0000) -16))
                    (arithmetic-shift (bitwise-and num-2 #xFF000000) -8))
                 #f))
       (define (stage-8)
         (values (+ (+ (arithmetic-shift (bitwise-and num-2 #xffff) 16)
                       (arithmetic-shift num-2 -24))
                    (arithmetic-shift (bitwise-and num-2 #xff0000) -8))
                 #f))
       (define (stage-9) (values (bitwise-not num-2) #f))
       (case c
         ([#\1] (and-right-left-add #xFFFFFF80 7 25))
         ([#\2] (and-right-left-add #xFFFFFFF0 4 28))
         ([#\3] (and-right-left-add #xFFFFFFF8 3 29))
         ([#\4] (left-right-add 1 31))
         ([#\5] (left-right-add 5 27))
         ([#\6] (left-right-add 12 20))
         ([#\7] (stage-7))
         ([#\8] (stage-8))
         ([#\9] (stage-9))
         (else (values num-1 flag))))))
 (32-bit-truncate num-1))

(module+ test

 (require rackunit)
 (define (own-test-calc-pass passwd nonce expected)
   (let* ((res (own-calc-pass passwd nonce))
          (msg (format "~a ~a ~a ~a" passwd nonce res expected)))
     (string-append (if (= res expected) "PASS" "FAIL") " " msg)))


 (own-test-calc-pass "12345" "603356072" 25280520)
 (own-test-calc-pass "12345" "410501656" 119537670))</lang>

Swift

<lang swift> func openAuthenticationResponse(_password: String, operations: String) -> String? {

   var num1 = UInt32(0)
   var num2 = UInt32(0)
   var start = true
   let password = UInt32(_password)!
   for c in operations {
       if (c != "0") {
           if start {
               num2 = password
           }
           start = false
       }
       switch c {
       case "1":
           num1 = (num2 & 0xffffff80) >> 7
           num2 = num2 << 25
       case "2":
           num1 = (num2 & 0xfffffff0) >> 4
           num2 = num2 << 28
       case "3":
           num1 = (num2 & 0xfffffff8) >> 3
           num2 = num2 << 29
       case "4":
           num1 = num2 << 1
           num2 = num2 >> 31
       case "5":
           num1 = num1 << 5
           num2 = num2 >> 27
       case "6":
           num1 = num2 << 12
           num2 = num2 >> 20
       case "7":
           num1 = (num2 & 0x0000ff00) | ((num2 & 0x000000ff) << 24) | ((num2 & 0x00ff0000) >> 16)
           num2 = (num2 & 0xff000000) >> 8
       case "8":
           num1 = ((num2 & 0x0000ffff) << 16) | (num2 >> 24)
           num2 = (num2 & 0x00ff0000) >> 8
       case "9":
           num1 = ~num2
       case "0":
           num1 = num2
       default:
           print("unexpected char \(c)")
           return nil
       }
       if (c != "9") && (c != "0") {
           num1 |= num2
       }
       num2 = num1
   }
   return String(num1)

} </lang>