VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Crypto/rdrand_ml.asm
blob: 4b85f7fc90aba4440aec2fe23003d6b3b8ec5a9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 Derived from source code of TrueCrypt 7.1a, which is
 Cop
;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
;;              Copyright assigned to the Crypto++ project.

;; This ASM file provides RDRAND to downlevel Microsoft tool chains.
;; Everything "just works" under Visual Studio. Other platforms will
;; have to run MASM/MASM-64 and then link to the object files.

;; set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh
;; set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi
;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\ml.exe" %ASFLAGS% /Fo rdrand-x86.obj /c rdrand.asm
;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64\ml64.exe" %ASFLAGS64% /Fo rdrand-x64.obj /c rdrand.asm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TITLE    MASM_RDRAND_GenerateBlock source file
SUBTITLE Microsoft specific ASM code to utilize RDRAND for down level Microsoft toolchains

PUBLIC MASM_RDRAND_GenerateBlock

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; C/C++ Function prototypes (both are fastcall)
;;   X86:
;;      extern "C" void __fastcall MASM_RDRAND_GenerateBlock(byte* ptr, size_t size);
;;   X64:
;;      extern "C" void __fastcall MASM_RDRAND_GenerateBlock(byte* ptr, size_t size);

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

IFDEF _M_X86    ;; Set via the command line

.486
.MODEL FLAT

;; Fastcall calling conventions exports
ALIAS <@MASM_RDRAND_GenerateBlock@8> = <MASM_RDRAND_GenerateBlock>

ENDIF

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

IFDEF _M_X86    ;; Set via the command line

.CODE
ALIGN   8
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

;; No need for Load_Arguments due to fastcall
;;   ECX (in): arg1, byte* buffer
;;   EDX (in): arg2, size_t bsize

MASM_RDRAND_GenerateBlock PROC   ;; arg1:DWORD, arg2:DWORD

    MWSIZE EQU 04h    ;; machine word size
    buffer EQU ecx
    bsize  EQU edx

            ;; Top of While loop
RDRAND_GenerateBlock_Top:

            ;; Check remaining size
    cmp     bsize, 0
    je      RDRAND_GenerateBlock_Return

RDRAND_Call_EAX:
            ;; RDRAND is not available prior to VS2012. Just emit
            ;;   the byte codes using DB. This is `rdrand eax`.
    DB      0Fh, 0C7h, 0F0h

            ;; If CF=1, the number returned by RDRAND is valid.
            ;; If CF=0, a random number was not available.

            ;; Retry immediately
    jnc     RDRAND_Call_EAX

RDRAND_succeeded:

    cmp     bsize, MWSIZE
    jb      RDRAND_Partial_Machine_Word

RDRAND_Full_Machine_Word:

    mov     DWORD PTR [buffer], eax
    add     buffer, MWSIZE        ;; No need for Intel Core 2 slow workarounds, like
    sub     bsize, MWSIZE         ;;   `lea buffer,[buffer+MWSIZE]` for faster adds

            ;; Continue
    jmp     RDRAND_GenerateBlock_Top

            ;; 1,2,3 bytes remain
RDRAND_Partial_Machine_Word:

            ;; Test bit 1 to see if size is at least 2
    test    bsize, 2
    jz      RDRAND_Bit_1_Not_Set

    mov     WORD PTR [buffer], ax
    shr     eax, 16
    add     buffer, 2

RDRAND_Bit_1_Not_Set:

            ;; Test bit 0 to see if size is at least 1
    test    bsize, 1
    jz      RDRAND_Bit_0_Not_Set

    mov     BYTE PTR [buffer], al
    ;; shr     ax, 8
    ;; add     buffer, 1

RDRAND_Bit_0_Not_Set:

            ;; We've hit all the bits

RDRAND_GenerateBlock_Return:

            ;; Clear artifacts
    xor     eax, eax
    ret

MASM_RDRAND_GenerateBlock ENDP

ENDIF    ;; _M_X86

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

IFDEF _M_X64    ;; Set via the command line

.CODE
ALIGN   16
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

;; No need for Load_Arguments due to fastcall
;;   RCX (in): arg1, byte* buffer
;;   RDX (in): arg2, size_t bsize

MASM_RDRAND_GenerateBlock PROC   ;; arg1:QWORD, arg2:QWORD

    MWSIZE EQU 08h    ;; machine word size
    buffer EQU rcx
    bsize  EQU rdx

            ;; Top of While loop
RDRAND_GenerateBlock_Top:

            ;; Check remaining size
    cmp     bsize, 0
    je      RDRAND_GenerateBlock_Return

RDRAND_Call_RAX:
            ;; RDRAND is not available prior to VS2012. Just emit
            ;;   the byte codes using DB. This is `rdrand rax`.
    DB      048h, 0Fh, 0C7h, 0F0h

            ;; If CF=1, the number returned by RDRAND is valid.
            ;; If CF=0, a random number was not available.

            ;; Retry immediately
    jnc     RDRAND_Call_RAX

RDRAND_succeeded:

    cmp     bsize, MWSIZE
    jb      RDRAND_Partial_Machine_Word

RDRAND_Full_Machine_Word:

    mov     QWORD PTR [buffer], rax
    add     buffer, MWSIZE
    sub     bsize, MWSIZE

            ;; Continue
    jmp     RDRAND_GenerateBlock_Top

            ;; 1,2,3,4,5,6,7 bytes remain
RDRAND_Partial_Machine_Word:

            ;; Test bit 2 to see if size is at least 4
    test    bsize, 4
    jz      RDRAND_Bit_2_Not_Set

    mov     DWORD PTR [buffer], eax
    shr     rax, 32
    add     buffer, 4

RDRAND_Bit_2_Not_Set:

            ;; Test bit 1 to see if size is at least 2
    test    bsize, 2
    jz      RDRAND_Bit_1_Not_Set

    mov     WORD PTR [buffer], ax
    shr     eax, 16
    add     buffer, 2

RDRAND_Bit_1_Not_Set:

            ;; Test bit 0 to see if size is at least 1
    test    bsize, 1
    jz      RDRAND_Bit_0_Not_Set

    mov     BYTE PTR [buffer], al
    ;; shr     ax, 8
    ;; add     buffer, 1

RDRAND_Bit_0_Not_Set:

            ;; We've hit all the bits

RDRAND_GenerateBlock_Return:

            ;; Clear artifacts
    xor     rax, rax
    ret

MASM_RDRAND_GenerateBlock ENDP

ENDIF    ;; _M_X64

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

END