.globl des_key_schedule @ void des_key_schedule(unsigned char key[96])
.globl des_encrypt      @ void des_encrypt(unsigned char buffer[8], const unsigned char key[96])
.globl des_decrypt      @ void des_decrypt(unsigned char buffer[8], const unsigned char key[96])

.section .text,"ax",%progbits

.balign 64

sbox1: .long    4210944,          0,      16384,    4210945,    4210689,      16641,          1,      16384,        256,    4210944,    4210945,        256,    4194561,    4210689,    4194304,          1
       .long        257,    4194560,    4194560,      16640,      16640,    4210688,    4210688,    4194561,      16385,    4194305,    4194305,      16385,          0,        257,      16641,    4194304
       .long      16384,    4210945,          1,    4210688,    4210944,    4194304,    4194304,        256,    4210689,      16384,      16640,    4194305,        256,          1,    4194561,      16641
       .long    4210945,      16385,    4210688,    4194561,    4194305,        257,      16641,    4210944,        257,    4194560,    4194560,          0,      16385,      16640,          0,    4210689
sbox2: .long  537141256,  536879104,       8192,     270344,     262144,          8,  537133064,  536879112,  536870920,  537141256,  537141248,  536870912,  536879104,     262144,          8,  537133064
       .long     270336,     262152,  536879112,          0,  536870912,       8192,     270344,  537133056,     262152,  536870920,          0,     270336,       8200,  537141248,  537133056,       8200
       .long          0,     270344,  537133064,     262144,  536879112,  537133056,  537141248,       8192,  537133056,  536879104,          8,  537141256,     270344,          8,       8192,  536870912
       .long       8200,  537141248,     262144,  536870920,     262152,  536879112,  536870920,     262152,     270336,          0,  536879104,       8200,  536870912,  537133064,  537141256,     270336
sbox3: .long        130,   33587328,          0,   33587202,   33554560,          0,      32898,   33554560,      32770,   33554434,   33554434,      32768,   33587330,      32770,   33587200,        130
       .long   33554432,          2,   33587328,        128,      32896,   33587200,   33587202,      32898,   33554562,      32896,      32768,   33554562,          2,   33587330,        128,   33554432
       .long   33587328,   33554432,      32770,        130,      32768,   33587328,   33554560,          0,        128,      32770,   33587330,   33554560,   33554434,        128,          0,   33587202
       .long   33554562,      32768,   33554432,   33587330,          2,      32898,      32896,   33554434,   33587200,   33554562,        130,   33587200,      32898,          2,   33587202,      32896
sbox4: .long 1075841024, 1073743904, 1073743904,         32,    2099232, 1075839008, 1075838976, 1073743872,          0,    2099200,    2099200, 1075841056, 1073741856,          0,    2097184, 1075838976
       .long 1073741824,       2048,    2097152, 1075841024,         32,    2097152, 1073743872,       2080, 1075839008, 1073741824,       2080,    2097184,       2048,    2099232, 1075841056, 1073741856
       .long    2097184, 1075838976,    2099200, 1075841056, 1073741856,          0,          0,    2099200,       2080,    2097184, 1075839008, 1073741824, 1075841024, 1073743904, 1073743904,         32
       .long 1075841056, 1073741856, 1073741824,       2048, 1075838976, 1073743872,    2099232, 1075839008, 1073743872,       2080,    2097152, 1075841024,         32,    2097152,       2048,    2099232
sbox5: .long         64,    8519744,    8519680,  276824128,     131072,         64,  268435456,    8519680,  268566592,     131072,    8388672,  268566592,  276824128,  276955136,     131136,  268435456
       .long    8388608,  268566528,  268566528,          0,  268435520,  276955200,  276955200,    8388672,  276955136,  268435520,          0,  276824064,    8519744,    8388608,  276824064,     131136
       .long     131072,  276824128,         64,    8388608,  268435456,    8519680,  276824128,  268566592,    8388672,  268435456,  276955136,    8519744,  268566592,         64,    8388608,  276955136
       .long  276955200,     131136,  276824064,  276955200,    8519680,          0,  268566528,  276824064,     131136,    8388672,  268435520,     131072,          0,  268566528,    8519744,  268435520
sbox6: .long  134217732,  135266304,       4096,  135270404,  135266304,          4,  135270404,    1048576,  134221824,    1052676,    1048576,  134217732,    1048580,  134221824,  134217728,       4100
       .long          0,    1048580,  134221828,       4096,    1052672,  134221828,          4,  135266308,  135266308,          0,    1052676,  135270400,       4100,    1052672,  135270400,  134217728
       .long  134221824,          4,  135266308,    1052672,  135270404,    1048576,       4100,  134217732,    1048576,  134221824,  134217728,       4100,  134217732,  135270404,    1052672,  135266304
       .long    1052676,  135270400,          0,  135266308,          4,       4096,  135266304,    1052676,       4096,    1048580,  134221828,          0,  135270400,  134217728,    1048580,  134221828
sbox7: .long     524288, 2164785152, 2164261376,          0,        512, 2164261376, 2148008448,   17302016, 2164785664,     524288,          0, 2164260864, 2147483648,   16777216, 2164785152, 2147484160
       .long   16777728, 2148008448, 2148007936,   16777728, 2164260864,   17301504,   17302016, 2148007936,   17301504,        512, 2147484160, 2164785664,     524800, 2147483648,   16777216,     524800
       .long   16777216,     524800,     524288, 2164261376, 2164261376, 2164785152, 2164785152, 2147483648, 2148007936,   16777216,   16777728,     524288,   17302016, 2147484160, 2148008448,   17302016
       .long 2147484160, 2164260864, 2164785664,   17301504,     524800,          0, 2147483648, 2164785664,          0, 2148008448,   17301504,        512, 2164260864,   16777728,        512, 2148007936
sbox8: .long   67109904,       1024,      65536,   67175440,   67108864,   67109904,         16,   67108864,      65552,   67174400,   67175440,      66560,   67175424,      66576,       1024,         16
       .long   67174400,   67108880,   67109888,       1040,      66560,      65552,   67174416,   67175424,       1040,          0,          0,   67174416,   67108880,   67109888,      66576,      65536
       .long      66576,      65536,   67175424,       1024,         16,   67174416,       1024,      66576,   67109888,         16,   67108880,   67174400,   67174416,   67108864,      65536,   67109904
       .long          0,   67175440,      65552,   67108880,   67174400,   67109888,   67109904,          0,   67175440,      66560,      66560,       1040,       1040,      65552,   67108864,   67175424

pc_2: .long        0,   524288,        1,   524289,   131072,   655360,   131073,   655361,      256,   524544,      257,   524545,   131328,   655616,   131329,   655617
      .long        0,   262144,    16384,   278528,       16,   262160,    16400,   278544,       64,   262208,    16448,   278592,       80,   262224,    16464,   278608
      .long        0,        0,     4096,     4096,  2097152,  2097152,  2101248,  2101248,      512,      512,     4608,     4608,  2097664,  2097664,  2101760,  2101760
      .long        0,        2,  8388608,  8388610,    32768,    32770,  8421376,  8421378,       32,       34,  8388640,  8388642,    32800,    32802,  8421408,  8421410
      .long        0,  4194304,        0,  4194304,     1024,  4195328,     1024,  4195328,        4,  4194308,        4,  4194308,     1028,  4195332,     1028,  4195332
      .long        0,     8192,        0,     8192,     2048,    10240,     2048,    10240,  1048576,  1056768,  1048576,  1056768,  1050624,  1058816,  1050624,  1058816
      .long        0,        0,      128,      128,        8,        8,      136,      136,    65536,    65536,    65664,    65664,    65544,    65544,    65672,    65672
      .long        0,        2,   131072,   131074,  2097152,  2097154,  2228224,  2228226,        1,        3,   131073,   131075,  2097153,  2097155,  2228225,  2228227
      .long        0,     8192,      128,     8320,        0,     8192,      128,     8320,        4,     8196,      132,     8324,        4,     8196,      132,     8324
      .long        0,  1048576,        0,  1048576,      512,  1049088,      512,  1049088,    65536,  1114112,    65536,  1114112,    66048,  1114624,    66048,  1114624
      .long        0,  8388608,       16,  8388624,        0,  8388608,       16,  8388624,     2048,  8390656,     2064,  8390672,     2048,  8390656,     2064,  8390672
      .long        0,    16384,       32,    16416,   524288,   540672,   524320,   540704,     4096,    20480,     4128,    20512,   528384,   544768,   528416,   544800
      .long        0,     1024,        8,     1032,    32768,    33792,    32776,    33800,  4194304,  4195328,  4194312,  4195336,  4227072,  4228096,  4227080,  4228104
      .long        0,       64,        0,       64,   262144,   262208,   262144,   262208,      256,      320,      256,      320,   262400,   262464,   262400,   262464

des_key_schedule:
    stmdb   sp!, {r4-r6}                @ save registers
    mov     r4, #0                      @ temporary variable to hold Kn
    sub     r12, pc, #912               @ pointer to PC-2
    ldmia   r0, {r1-r2}                 @ load K
    eor     r3, r1, r2, LSR #4
    bic     r3, #240
    bic     r3, #61440
    bic     r3, #15728640
    bic     r3, #4026531840
    eor     r1, r3
    eor     r2, r3, LSL #4
    eor     r3, r1, r1, LSL #18
    bic     r3, #255
    bic     r3, #65280
    bic     r3, #3342336
    bic     r3, #855638016
    eor     r1, r3
    eor     r1, r3, LSR #18
    eor     r3, r2, r2, LSL #18
    bic     r3, #255
    bic     r3, #65280
    bic     r3, #3342336
    bic     r3, #855638016
    eor     r2, r3
    eor     r2, r3, LSR #18
    eor     r3, r1, r2, LSR #1
    bic     r3, #170
    bic     r3, #43520
    bic     r3, #11141120
    bic     r3, #2852126720
    eor     r1, r3
    eor     r2, r3, LSL #1
    eor     r3, r2, r1, LSR #8
    bic     r3, #65280
    bic     r3, #4278190080
    eor     r2, r3
    eor     r1, r3, LSL #8
    eor     r3, r1, r2, LSR #1
    bic     r3, #170
    bic     r3, #43520
    bic     r3, #11141120
    bic     r3, #2852126720
    eor     r1, r3
    eor     r2, r3, LSL #1
    mov     r2, r2, LSL #8
    orr     r2, r1, LSR #28
    eor     r3, r2, r2, ROR #16
    bic     r3, #16711680
    mov     r2, r2, ROR #8
    eor     r2, r3, LSR #8              @ D
    bic     r1, #4026531840             @ C
    mov     r6, #33024
    orr     r6, #3
.Ldes_key_schedule_round:
    movs    r1, r1, LSR #1              @ shift C
    orrcs   r1, #134217728
    movs    r2, r2, LSR #1              @ shift D
    orrcs   r2, #134217728
    movs    r6, r6, LSR #1
    bcs     .Ldes_key_schedule_round_skip_2nd_rotation
    movs    r1, r1, LSR #1              @ shift C in rounds 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15
    orrcs   r1, #134217728
    movs    r2, r2, LSR #1              @ shift D in rounds 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15
    orrcs   r2, #134217728
.Ldes_key_schedule_round_skip_2nd_rotation:
    mov     r5, #7                      @ 28 bits to permute
.Ldes_key_schedule_round_pc_2_a:
    and     r3, r1, #15
    ldr     r3, [r12, r3, LSL #2]       @ next group of bits of Kn
    mov     r1, r1, ROR #4
    orr     r4, r3
    add     r12, #64
    subs    r5, #1
    bne     .Ldes_key_schedule_round_pc_2_a
    mov     r1, r1, LSR #4              @ C
    strb    r4, [r0], #1                @ store 1st byte of Kn
    mov     r4, r4, LSR #8
    strb    r4, [r0], #1                @ store 2nd byte of Kn
    mov     r4, r4, LSR #8
    strb    r4, [r0], #1                @ store 3rd byte of Kn
    mov     r4, r4, LSR #8              @ r4 = 0
    mov     r5, #7                      @ 28 bits to permute
.Ldes_key_schedule_round_pc_2_b:
    and     r3, r2, #15
    ldr     r3, [r12, r3, LSL #2]       @ next group of bits of Kn
    mov     r2, r2, ROR #4
    orr     r4, r3
    add     r12, #64
    subs    r5, #1
    bne     .Ldes_key_schedule_round_pc_2_b
    mov     r2, r2, LSR #4              @ D
    strb    r4, [r0], #1                @ store 4th byte of Kn
    mov     r4, r4, LSR #8
    strb    r4, [r0], #1                @ store 5th byte of Kn
    mov     r4, r4, LSR #8
    strb    r4, [r0], #1                @ store 6th byte of Kn
    mov     r4, r4, LSR #8              @ r4 = 0
    sub     r12, #896                   @ pointer to PC-2
    teq     r6, #0
    bne     .Ldes_key_schedule_round
    ldmia   sp!, {r4-r6}                @ restore saved registers
    mov     pc, lr

des_encrypt:
    mov     r12, #0
    b       .Ldes_crypto
des_decrypt:
    mov     r12, #12
    add     r1, #90                     @ last round key
.Ldes_crypto:
    stmdb   sp!, {r4-r9, r11}
    ldmia   r0, {r2-r3}
    eor     r4, r2, r2, ROR #16         @ IP start
    bic     r4, #16711680
    mov     r2, r2, ROR #8
    eor     r2, r4, LSR #8
    eor     r4, r3, r3, ROR #16
    bic     r4, #16711680
    mov     r3, r3, ROR #8
    eor     r3, r4, LSR #8
    mov     r2, r2, ROR #4
    eor     r4, r3, r2
    bic     r4, #240
    bic     r4, #61440
    bic     r4, #15728640
    bic     r4, #4026531840
    eor     r2, r4
    eor     r3, r4
    mov     r2, r2, ROR #12
    eor     r4, r3, r2
    bic     r4, #16711680
    bic     r4, #4278190080
    eor     r2, r4
    eor     r3, r4
    mov     r2, r2, ROR #14
    eor     r4, r3, r2
    bic     r4, #51
    bic     r4, #13056
    bic     r4, #3342336
    bic     r4, #855638016
    eor     r2, r4
    eor     r3, r4
    mov     r2, r2, ROR #26
    eor     r4, r3, r2
    bic     r4, #255
    bic     r4, #16711680
    eor     r2, r4
    eor     r3, r4
    mov     r2, r2, ROR #9
    eor     r4, r3, r2
    bic     r4, #170
    bic     r4, #43520
    bic     r4, #11141120
    bic     r4, #2852126720
    eor     r2, r4
    eor     r3, r4
    mov     r3, r3, ROR #1
    mov     r4, #0
    sub     r11, pc, #3552
    mov     r9, #16
.Ldes_crypto_round:
    mov     r6, #0
    mov     r8, #2
.Ldes_crypto_round_loop:
    ldrb    r5, [r1], #1
    orr     r4, r5, LSL #8
    ldrb    r5, [r1], #1
    orr     r4, r5, LSL #16
    ldrb    r5, [r1], #1
    orr     r4, r5, LSL #24             @ 3 bytes of K
    mov     r7, #4
.Ldes_crypto_round_loop_internal:
    eor     r5, r4, r3                  @ next bits of K + E(R)
    mov     r5, r5, LSR #26             @ Bn
    ldr     r5, [r11, r5, LSL #2]       @ P(Sn(Bn))
    mov     r3, r3, ROR #28
    mov     r4, r4, LSL #6
    orr     r6, r5                      @ next bits of f(R, K)
    add     r11, #256                   @ pointer to next sbox
    subs    r7, #1
    bne     .Ldes_crypto_round_loop_internal
    subs    r8, #1
    bne     .Ldes_crypto_round_loop
    sub     r1, r12
    eor     r6, r2                      @ L + f(R, K)
    mov     r2, r3                      @ L' = R
    mov     r3, r6                      @ R' = L + f(R, K)
    sub     r11, #2048                  @ pointer to sbox1
    subs    r9, #1
    bne     .Ldes_crypto_round
    eor     r2, r3                      @ L' = L + R
    eor     r3, r2                      @ R' = R + L + R = L
    eor     r2, r3                      @ L' = L + R + L = R
    mov     r3, r3, ROR #31             @ FP start
    eor     r4, r3, r2
    bic     r4, #170
    bic     r4, #43520
    bic     r4, #11141120
    bic     r4, #2852126720
    eor     r2, r4
    eor     r3, r4
    mov     r2, r2, ROR #23
    eor     r4, r3, r2
    bic     r4, #255
    bic     r4, #16711680
    eor     r2, r4
    eor     r3, r4
    mov     r2, r2, ROR #6
    eor     r4, r3, r2
    bic     r4, #51
    bic     r4, #13056
    bic     r4, #3342336
    bic     r4, #855638016
    eor     r2, r4
    eor     r3, r4
    mov     r2, r2, ROR #18
    eor     r4, r3, r2
    bic     r4, #16711680
    bic     r4, #4278190080
    eor     r2, r4
    eor     r3, r4
    mov     r2, r2, ROR #20
    eor     r4, r3, r2
    bic     r4, #240
    bic     r4, #61440
    bic     r4, #15728640
    bic     r4, #4026531840
    eor     r2, r4
    eor     r3, r4
    mov     r2, r2, ROR #28
    eor     r4, r2, r2, ROR #16
    bic     r4, #16711680
    mov     r2, r2, ROR #8
    eor     r2, r4, LSR #8
    eor     r4, r3, r3, ROR #16
    bic     r4, #16711680
    mov     r3, r3, ROR #8
    eor     r3, r4, LSR #8
    stmia   r0, {r2-r3}
    ldmia   sp!, {r4-r9, r11}
    mov     pc, lr
