Repository: lucasfrag/Kali-Linux-Tools-Interface
Branch: master
Commit: a7fbe14ed136
Files: 99
Total size: 2.1 MB
Directory structure:
gitextract__z4wb0uk/
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.md
│ └── feature_request.md
├── CITATION.cff
├── LICENSE
├── README.md
├── assets/
│ ├── css/
│ │ ├── argon.css
│ │ ├── bootstrap.css
│ │ └── styles.css
│ ├── database.sql
│ ├── includes/
│ │ ├── config.php
│ │ ├── footer.php
│ │ ├── head.php
│ │ ├── header.php
│ │ ├── list-commands.php
│ │ └── tools-categories.php
│ ├── js/
│ │ ├── argon.js
│ │ └── bootstrap.js
│ ├── libraries/
│ │ └── phpseclib/
│ │ ├── Crypt/
│ │ │ ├── AES.php
│ │ │ ├── Base.php
│ │ │ ├── Blowfish.php
│ │ │ ├── DES.php
│ │ │ ├── Hash.php
│ │ │ ├── RC2.php
│ │ │ ├── RC4.php
│ │ │ ├── RSA.php
│ │ │ ├── Random.php
│ │ │ ├── Rijndael.php
│ │ │ ├── TripleDES.php
│ │ │ └── Twofish.php
│ │ ├── File/
│ │ │ ├── ANSI.php
│ │ │ ├── ASN1.php
│ │ │ └── X509.php
│ │ ├── Math/
│ │ │ └── BigInteger.php
│ │ ├── Net/
│ │ │ ├── SCP.php
│ │ │ ├── SFTP/
│ │ │ │ └── Stream.php
│ │ │ ├── SFTP.php
│ │ │ ├── SSH1.php
│ │ │ └── SSH2.php
│ │ ├── System/
│ │ │ ├── SSH/
│ │ │ │ └── Agent.php
│ │ │ └── SSH_Agent.php
│ │ ├── bootstrap.php
│ │ └── openssl.cnf
│ └── vendor/
│ ├── @fortawesome/
│ │ └── fontawesome-free/
│ │ └── LICENSE.txt
│ ├── anchor-js/
│ │ └── banner.js
│ ├── chart.js/
│ │ └── dist/
│ │ └── Chart.extension.js
│ ├── holderjs/
│ │ └── package.js
│ ├── jquery/
│ │ └── dist/
│ │ └── core.js
│ ├── jquery.scrollbar/
│ │ ├── index.js
│ │ ├── jquery.scrollbar.css
│ │ ├── license-gpl.txt
│ │ ├── license-mit.txt
│ │ ├── meteor/
│ │ │ └── tests.js
│ │ ├── package.js
│ │ ├── sass/
│ │ │ └── config.rb
│ │ └── scrollbar.jquery.json
│ ├── nucleo/
│ │ └── css/
│ │ ├── nucleo-svg.css
│ │ └── nucleo.css
│ ├── onscreen/
│ │ └── dist/
│ │ └── on-screen.es6.js
│ └── prismjs/
│ ├── components/
│ │ └── index.js
│ ├── components.js
│ ├── components.json
│ ├── plugins/
│ │ ├── autolinker/
│ │ │ └── prism-autolinker.css
│ │ ├── command-line/
│ │ │ └── prism-command-line.css
│ │ ├── line-highlight/
│ │ │ └── prism-line-highlight.css
│ │ ├── line-numbers/
│ │ │ └── prism-line-numbers.css
│ │ ├── previewers/
│ │ │ └── prism-previewers.css
│ │ ├── show-invisibles/
│ │ │ └── prism-show-invisibles.css
│ │ ├── toolbar/
│ │ │ └── prism-toolbar.css
│ │ ├── unescaped-markup/
│ │ │ └── prism-unescaped-markup.css
│ │ └── wpd/
│ │ └── prism-wpd.css
│ ├── prism.js
│ └── themes/
│ ├── prism-coy.css
│ ├── prism-dark.css
│ ├── prism-funky.css
│ ├── prism-okaidia.css
│ ├── prism-solarizedlight.css
│ ├── prism-tomorrow.css
│ ├── prism-twilight.css
│ └── prism.css
├── debian.php
├── delete-reports.php
├── gitbook/
│ ├── README.md
│ ├── arquitetura.md
│ ├── mapa-mental.md
│ ├── mvp-canvas.md
│ ├── personas.md
│ └── sprint-backlog.md
├── index.php
├── login-validation.php
├── login.php
├── logout.php
├── profile.php
├── reports.php
├── run.php
├── save-reports.php
├── selected-report.php
├── selected-tool.php
├── terminal.php
└── tools-list.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: CITATION.cff
================================================
cff-version: 1.2.0
message: "If you use this repository in your research, please cite it as follows."
title: "Kali Linux Tools Interface: Graphical Web Interface for Security Tools"
version: "v2.0.0"
doi: "10.5281/zenodo.17298710" # replace with the actual DOI after Zenodo integration
authors:
- family-names: "Fraga"
given-names: "Lucas"
orcid: "https://orcid.org/0009-0004-5936-5482" # optional, add if you have ORCID
repository-code:
type: "GitHub"
url: "https://github.com/lucasfrag/kali-linux-tools-interface"
date-released: "2025-10-08"
license: "MIT"
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 Lucas Fraga
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
Kali Linux Tools Interface
A graphical interface to use information security tools by the browser.
Explore the article »
(Available only in Brazilian Portuguese)
Report Bug
·
Request Feature
⚠️ ALERT 🚧
As I am involved in other projects, I am no longer supporting this project.
However, the code remains open to anyone who wants to download, test and modify. Thanks to everyone for your support! Enjoy 😉
## 🧩 Citation
If you use this repository in your research, please cite it as follows:
- BibTeX:
```
@software{Fraga_Kali_Linux_Tools_2025,
author = {Fraga, Lucas},
doi = {10.5281/zenodo.17298710},
license = {MIT},
month = oct,
title = {{Kali Linux Tools Interface: Graphical Web Interface for Security Tools}},
url = {{"type" => "GitHub", "url" => "https://github.com/lucasfrag/kali-linux-tools-interface"}},
version = {v2.0.0},
year = {2025}
}
```
## Getting Started
Kali Linux Tools Interface is a graphical interface to use information security tools by the browser. The project uses the Kali Linux tools as a reference because it is the distribution that has the largest package of native tools.
### Prerequisites
- A Debian-based distribution (preferably [Kali Linux](https://www.kali.org/))
- The information security tools installed
- Apache / Nginx service running
- SSH Service running
- Shell In A Box (if you want to use the Terminal)
- To install Shell In A Box , use the following command: `sudo apt-get install shellinabox`
### Installation
1. Extract the contents to the folder of your web server.
2. Create a database called `kali` in MySQL and import the file `assets/database.sql`.
3. Edit the file `assets/includes/config.php` and set yours settings.
4. Enjoy!
## Screenshots
### Dashboard
### Tools list
### Choose and use!
### More screenshots:
Check the article for more screenshots!
## Built With
* [Argon Dashboard](https://demos.creative-tim.com/argon-dashboard/)
* [Bootstrap 4](https://getbootstrap.com)
* [PHP 7](https://php.net)
* [PHP Secure Communications Library](https://github.com/phpseclib/phpseclib)
* [JQuery](https://jquery.com)
## License
Distributed under the MIT License. See LICENSE for more information.
================================================
FILE: assets/css/argon.css
================================================
/*!
=========================================================
* Argon Dashboard - v1.0.0
=========================================================
* Product Page: https://www.creative-tim.com/product/argon-dashboard
* Copyright 2018 Creative Tim (https://www.creative-tim.com)
* Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard/blob/master/LICENSE.md)
* Coded by Creative Tim
=========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
:root
{
--blue: #5e72e4;
--indigo: #5603ad;
--purple: #8965e0;
--pink: #f3a4b5;
--red: #f5365c;
--orange: #fb6340;
--yellow: #ffd600;
--green: #2dce89;
--teal: #11cdef;
--cyan: #2bffc6;
--white: #fff;
--gray: #8898aa;
--gray-dark: #32325d;
--light: #ced4da;
--lighter: #e9ecef;
--primary: #5e72e4;
--secondary: #f7fafc;
--success: #2dce89;
--info: #11cdef;
--warning: #fb6340;
--danger: #f5365c;
--light: #adb5bd;
--dark: #212529;
--default: #172b4d;
--white: #fff;
--neutral: #fff;
--darker: black;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
--breakpoint-md: 768px;
--breakpoint-lg: 992px;
--breakpoint-xl: 1200px;
--font-family-sans-serif: Open Sans, sans-serif;
--font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
}
*,
*::before,
*::after
{
box-sizing: border-box;
}
html
{
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@-ms-viewport
{
width: device-width;
}
article,
aside,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section
{
display: block;
}
body
{
font-family: Open Sans, sans-serif;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
margin: 0;
text-align: left;
color: #525f7f;
background-color: #f8f9fe;
}
[tabindex='-1']:focus
{
outline: 0 !important;
}
hr
{
overflow: visible;
box-sizing: content-box;
height: 0;
}
h1,
h2,
h3,
h4,
h5,
h6
{
margin-top: 0;
margin-bottom: .5rem;
}
p
{
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title]
{
cursor: help;
text-decoration: underline;
text-decoration: underline dotted;
border-bottom: 0;
-webkit-text-decoration: underline dotted;
}
address
{
font-style: normal;
line-height: inherit;
margin-bottom: 1rem;
}
ol,
ul,
dl
{
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol
{
margin-bottom: 0;
}
dt
{
font-weight: 600;
}
dd
{
margin-bottom: .5rem;
margin-left: 0;
}
blockquote
{
margin: 0 0 1rem;
}
dfn
{
font-style: italic;
}
b,
strong
{
font-weight: bolder;
}
small
{
font-size: 80%;
}
sub,
sup
{
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub
{
bottom: -.25em;
}
sup
{
top: -.5em;
}
a
{
text-decoration: none;
color: #5e72e4;
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:hover
{
text-decoration: none;
color: #233dd2;
}
a:not([href]):not([tabindex])
{
text-decoration: none;
color: inherit;
}
a:not([href]):not([tabindex]):hover,
a:not([href]):not([tabindex]):focus
{
text-decoration: none;
color: inherit;
}
a:not([href]):not([tabindex]):focus
{
outline: 0;
}
pre,
code,
kbd,
samp
{
font-family: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
font-size: 1em;
}
pre
{
overflow: auto;
margin-top: 0;
margin-bottom: 1rem;
-ms-overflow-style: scrollbar;
}
figure
{
margin: 0 0 1rem;
}
img
{
vertical-align: middle;
border-style: none;
}
svg
{
overflow: hidden;
vertical-align: middle;
}
table
{
border-collapse: collapse;
}
caption
{
padding-top: 1rem;
padding-bottom: 1rem;
caption-side: bottom;
text-align: left;
color: #8898aa;
}
th
{
text-align: inherit;
}
label
{
display: inline-block;
margin-bottom: .5rem;
}
button
{
border-radius: 0;
}
button:focus
{
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea
{
font-family: inherit;
font-size: inherit;
line-height: inherit;
margin: 0;
}
button,
input
{
overflow: visible;
}
button,
select
{
text-transform: none;
}
button,
html [type='button'],
[type='reset'],
[type='submit']
{
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type='button']::-moz-focus-inner,
[type='reset']::-moz-focus-inner,
[type='submit']::-moz-focus-inner
{
padding: 0;
border-style: none;
}
input[type='radio'],
input[type='checkbox']
{
box-sizing: border-box;
padding: 0;
}
input[type='date'],
input[type='time'],
input[type='datetime-local'],
input[type='month']
{
-webkit-appearance: listbox;
}
textarea
{
overflow: auto;
resize: vertical;
}
fieldset
{
min-width: 0;
margin: 0;
padding: 0;
border: 0;
}
legend
{
font-size: 1.5rem;
line-height: inherit;
display: block;
width: 100%;
max-width: 100%;
margin-bottom: .5rem;
padding: 0;
white-space: normal;
color: inherit;
}
progress
{
vertical-align: baseline;
}
[type='number']::-webkit-inner-spin-button,
[type='number']::-webkit-outer-spin-button
{
height: auto;
}
[type='search']
{
outline-offset: -2px;
-webkit-appearance: none;
}
[type='search']::-webkit-search-cancel-button,
[type='search']::-webkit-search-decoration
{
-webkit-appearance: none;
}
::-webkit-file-upload-button
{
font: inherit;
-webkit-appearance: button;
}
output
{
display: inline-block;
}
summary
{
display: list-item;
cursor: pointer;
}
template
{
display: none;
}
[hidden]
{
display: none !important;
}
h1,
h2,
h3,
h4,
h5,
h6,
.h1,
.h2,
.h3,
.h4,
.h5,
.h6
{
font-family: inherit;
font-weight: 600;
line-height: 1.5;
margin-bottom: .5rem;
color: #32325d;
}
h1,
.h1
{
font-size: 1.625rem;
}
h2,
.h2
{
font-size: 1.25rem;
}
h3,
.h3
{
font-size: 1.0625rem;
}
h4,
.h4
{
font-size: .9375rem;
}
h5,
.h5
{
font-size: .8125rem;
}
h6,
.h6
{
font-size: .625rem;
}
.lead
{
font-size: 1.25rem;
font-weight: 300;
}
.display-1
{
font-size: 3.3rem;
font-weight: 600;
line-height: 1.5;
}
.display-2
{
font-size: 2.75rem;
font-weight: 600;
line-height: 1.5;
}
.display-3
{
font-size: 2.1875rem;
font-weight: 600;
line-height: 1.5;
}
.display-4
{
font-size: 1.6275rem;
font-weight: 600;
line-height: 1.5;
}
hr
{
margin-top: 2rem;
margin-bottom: 2rem;
border: 0;
border-top: 1px solid rgba(0, 0, 0, .1);
}
small,
.small
{
font-size: 80%;
font-weight: 400;
}
mark,
.mark
{
padding: .2em;
background-color: #fcf8e3;
}
.list-unstyled
{
padding-left: 0;
list-style: none;
}
.list-inline
{
padding-left: 0;
list-style: none;
}
.list-inline-item
{
display: inline-block;
}
.list-inline-item:not(:last-child)
{
margin-right: .5rem;
}
.initialism
{
font-size: 90%;
text-transform: uppercase;
}
.blockquote
{
font-size: 1.25rem;
margin-bottom: 1rem;
}
.blockquote-footer
{
font-size: 80%;
display: block;
color: #8898aa;
}
.blockquote-footer::before
{
content: '\2014 \00A0';
}
.img-fluid
{
max-width: 100%;
height: auto;
}
.img-thumbnail
{
max-width: 100%;
height: auto;
padding: .25rem;
border: 1px solid #dee2e6;
border-radius: .375rem;
background-color: #f8f9fe;
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.figure
{
display: inline-block;
}
.figure-img
{
line-height: 1;
margin-bottom: .5rem;
}
.figure-caption
{
font-size: 90%;
color: #8898aa;
}
code
{
font-size: 87.5%;
word-break: break-word;
color: #f3a4b5;
}
a > code
{
color: inherit;
}
kbd
{
font-size: 87.5%;
padding: .2rem .4rem;
color: #fff;
border-radius: .25rem;
background-color: #212529;
box-shadow: inset 0 -.1rem 0 rgba(0, 0, 0, .25);
}
kbd kbd
{
font-size: 100%;
font-weight: 600;
padding: 0;
box-shadow: none;
}
pre
{
font-size: 87.5%;
display: block;
color: #212529;
}
pre code
{
font-size: inherit;
word-break: normal;
color: inherit;
}
.pre-scrollable
{
overflow-y: scroll;
max-height: 340px;
}
.container
{
width: 100%;
margin-right: auto;
margin-left: auto;
padding-right: 15px;
padding-left: 15px;
}
@media (min-width: 576px)
{
.container
{
max-width: 540px;
}
}
@media (min-width: 768px)
{
.container
{
max-width: 720px;
}
}
@media (min-width: 992px)
{
.container
{
max-width: 960px;
}
}
@media (min-width: 1200px)
{
.container
{
max-width: 1140px;
}
}
.container-fluid
{
width: 100%;
margin-right: auto;
margin-left: auto;
padding-right: 15px;
padding-left: 15px;
}
.row
{
display: flex;
margin-right: -15px;
margin-left: -15px;
flex-wrap: wrap;
}
.no-gutters
{
margin-right: 0;
margin-left: 0;
}
.no-gutters > .col,
.no-gutters > [class*='col-']
{
padding-right: 0;
padding-left: 0;
}
.col-1,
.col-2,
.col-3,
.col-4,
.col-5,
.col-6,
.col-7,
.col-8,
.col-9,
.col-10,
.col-11,
.col-12,
.col,
.col-auto,
.col-sm-1,
.col-sm-2,
.col-sm-3,
.col-sm-4,
.col-sm-5,
.col-sm-6,
.col-sm-7,
.col-sm-8,
.col-sm-9,
.col-sm-10,
.col-sm-11,
.col-sm-12,
.col-sm,
.col-sm-auto,
.col-md-1,
.col-md-2,
.col-md-3,
.col-md-4,
.col-md-5,
.col-md-6,
.col-md-7,
.col-md-8,
.col-md-9,
.col-md-10,
.col-md-11,
.col-md-12,
.col-md,
.col-md-auto,
.col-lg-1,
.col-lg-2,
.col-lg-3,
.col-lg-4,
.col-lg-5,
.col-lg-6,
.col-lg-7,
.col-lg-8,
.col-lg-9,
.col-lg-10,
.col-lg-11,
.col-lg-12,
.col-lg,
.col-lg-auto,
.col-xl-1,
.col-xl-2,
.col-xl-3,
.col-xl-4,
.col-xl-5,
.col-xl-6,
.col-xl-7,
.col-xl-8,
.col-xl-9,
.col-xl-10,
.col-xl-11,
.col-xl-12,
.col-xl,
.col-xl-auto
{
position: relative;
width: 100%;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
.col
{
max-width: 100%;
flex-basis: 0;
flex-grow: 1;
}
.col-auto
{
width: auto;
max-width: none;
flex: 0 0 auto;
}
.col-1
{
max-width: 8.33333%;
flex: 0 0 8.33333%;
}
.col-2
{
max-width: 16.66667%;
flex: 0 0 16.66667%;
}
.col-3
{
max-width: 25%;
flex: 0 0 25%;
}
.col-4
{
max-width: 33.33333%;
flex: 0 0 33.33333%;
}
.col-5
{
max-width: 41.66667%;
flex: 0 0 41.66667%;
}
.col-6
{
max-width: 50%;
flex: 0 0 50%;
}
.col-7
{
max-width: 58.33333%;
flex: 0 0 58.33333%;
}
.col-8
{
max-width: 66.66667%;
flex: 0 0 66.66667%;
}
.col-9
{
max-width: 75%;
flex: 0 0 75%;
}
.col-10
{
max-width: 83.33333%;
flex: 0 0 83.33333%;
}
.col-11
{
max-width: 91.66667%;
flex: 0 0 91.66667%;
}
.col-12
{
max-width: 100%;
flex: 0 0 100%;
}
.order-first
{
order: -1;
}
.order-last
{
order: 13;
}
.order-0
{
order: 0;
}
.order-1
{
order: 1;
}
.order-2
{
order: 2;
}
.order-3
{
order: 3;
}
.order-4
{
order: 4;
}
.order-5
{
order: 5;
}
.order-6
{
order: 6;
}
.order-7
{
order: 7;
}
.order-8
{
order: 8;
}
.order-9
{
order: 9;
}
.order-10
{
order: 10;
}
.order-11
{
order: 11;
}
.order-12
{
order: 12;
}
.offset-1
{
margin-left: 8.33333%;
}
.offset-2
{
margin-left: 16.66667%;
}
.offset-3
{
margin-left: 25%;
}
.offset-4
{
margin-left: 33.33333%;
}
.offset-5
{
margin-left: 41.66667%;
}
.offset-6
{
margin-left: 50%;
}
.offset-7
{
margin-left: 58.33333%;
}
.offset-8
{
margin-left: 66.66667%;
}
.offset-9
{
margin-left: 75%;
}
.offset-10
{
margin-left: 83.33333%;
}
.offset-11
{
margin-left: 91.66667%;
}
@media (min-width: 576px)
{
.col-sm
{
max-width: 100%;
flex-basis: 0;
flex-grow: 1;
}
.col-sm-auto
{
width: auto;
max-width: none;
flex: 0 0 auto;
}
.col-sm-1
{
max-width: 8.33333%;
flex: 0 0 8.33333%;
}
.col-sm-2
{
max-width: 16.66667%;
flex: 0 0 16.66667%;
}
.col-sm-3
{
max-width: 25%;
flex: 0 0 25%;
}
.col-sm-4
{
max-width: 33.33333%;
flex: 0 0 33.33333%;
}
.col-sm-5
{
max-width: 41.66667%;
flex: 0 0 41.66667%;
}
.col-sm-6
{
max-width: 50%;
flex: 0 0 50%;
}
.col-sm-7
{
max-width: 58.33333%;
flex: 0 0 58.33333%;
}
.col-sm-8
{
max-width: 66.66667%;
flex: 0 0 66.66667%;
}
.col-sm-9
{
max-width: 75%;
flex: 0 0 75%;
}
.col-sm-10
{
max-width: 83.33333%;
flex: 0 0 83.33333%;
}
.col-sm-11
{
max-width: 91.66667%;
flex: 0 0 91.66667%;
}
.col-sm-12
{
max-width: 100%;
flex: 0 0 100%;
}
.order-sm-first
{
order: -1;
}
.order-sm-last
{
order: 13;
}
.order-sm-0
{
order: 0;
}
.order-sm-1
{
order: 1;
}
.order-sm-2
{
order: 2;
}
.order-sm-3
{
order: 3;
}
.order-sm-4
{
order: 4;
}
.order-sm-5
{
order: 5;
}
.order-sm-6
{
order: 6;
}
.order-sm-7
{
order: 7;
}
.order-sm-8
{
order: 8;
}
.order-sm-9
{
order: 9;
}
.order-sm-10
{
order: 10;
}
.order-sm-11
{
order: 11;
}
.order-sm-12
{
order: 12;
}
.offset-sm-0
{
margin-left: 0;
}
.offset-sm-1
{
margin-left: 8.33333%;
}
.offset-sm-2
{
margin-left: 16.66667%;
}
.offset-sm-3
{
margin-left: 25%;
}
.offset-sm-4
{
margin-left: 33.33333%;
}
.offset-sm-5
{
margin-left: 41.66667%;
}
.offset-sm-6
{
margin-left: 50%;
}
.offset-sm-7
{
margin-left: 58.33333%;
}
.offset-sm-8
{
margin-left: 66.66667%;
}
.offset-sm-9
{
margin-left: 75%;
}
.offset-sm-10
{
margin-left: 83.33333%;
}
.offset-sm-11
{
margin-left: 91.66667%;
}
}
@media (min-width: 768px)
{
.col-md
{
max-width: 100%;
flex-basis: 0;
flex-grow: 1;
}
.col-md-auto
{
width: auto;
max-width: none;
flex: 0 0 auto;
}
.col-md-1
{
max-width: 8.33333%;
flex: 0 0 8.33333%;
}
.col-md-2
{
max-width: 16.66667%;
flex: 0 0 16.66667%;
}
.col-md-3
{
max-width: 25%;
flex: 0 0 25%;
}
.col-md-4
{
max-width: 33.33333%;
flex: 0 0 33.33333%;
}
.col-md-5
{
max-width: 41.66667%;
flex: 0 0 41.66667%;
}
.col-md-6
{
max-width: 50%;
flex: 0 0 50%;
}
.col-md-7
{
max-width: 58.33333%;
flex: 0 0 58.33333%;
}
.col-md-8
{
max-width: 66.66667%;
flex: 0 0 66.66667%;
}
.col-md-9
{
max-width: 75%;
flex: 0 0 75%;
}
.col-md-10
{
max-width: 83.33333%;
flex: 0 0 83.33333%;
}
.col-md-11
{
max-width: 91.66667%;
flex: 0 0 91.66667%;
}
.col-md-12
{
max-width: 100%;
flex: 0 0 100%;
}
.order-md-first
{
order: -1;
}
.order-md-last
{
order: 13;
}
.order-md-0
{
order: 0;
}
.order-md-1
{
order: 1;
}
.order-md-2
{
order: 2;
}
.order-md-3
{
order: 3;
}
.order-md-4
{
order: 4;
}
.order-md-5
{
order: 5;
}
.order-md-6
{
order: 6;
}
.order-md-7
{
order: 7;
}
.order-md-8
{
order: 8;
}
.order-md-9
{
order: 9;
}
.order-md-10
{
order: 10;
}
.order-md-11
{
order: 11;
}
.order-md-12
{
order: 12;
}
.offset-md-0
{
margin-left: 0;
}
.offset-md-1
{
margin-left: 8.33333%;
}
.offset-md-2
{
margin-left: 16.66667%;
}
.offset-md-3
{
margin-left: 25%;
}
.offset-md-4
{
margin-left: 33.33333%;
}
.offset-md-5
{
margin-left: 41.66667%;
}
.offset-md-6
{
margin-left: 50%;
}
.offset-md-7
{
margin-left: 58.33333%;
}
.offset-md-8
{
margin-left: 66.66667%;
}
.offset-md-9
{
margin-left: 75%;
}
.offset-md-10
{
margin-left: 83.33333%;
}
.offset-md-11
{
margin-left: 91.66667%;
}
}
@media (min-width: 992px)
{
.col-lg
{
max-width: 100%;
flex-basis: 0;
flex-grow: 1;
}
.col-lg-auto
{
width: auto;
max-width: none;
flex: 0 0 auto;
}
.col-lg-1
{
max-width: 8.33333%;
flex: 0 0 8.33333%;
}
.col-lg-2
{
max-width: 16.66667%;
flex: 0 0 16.66667%;
}
.col-lg-3
{
max-width: 25%;
flex: 0 0 25%;
}
.col-lg-4
{
max-width: 33.33333%;
flex: 0 0 33.33333%;
}
.col-lg-5
{
max-width: 41.66667%;
flex: 0 0 41.66667%;
}
.col-lg-6
{
max-width: 50%;
flex: 0 0 50%;
}
.col-lg-7
{
max-width: 58.33333%;
flex: 0 0 58.33333%;
}
.col-lg-8
{
max-width: 66.66667%;
flex: 0 0 66.66667%;
}
.col-lg-9
{
max-width: 75%;
flex: 0 0 75%;
}
.col-lg-10
{
max-width: 83.33333%;
flex: 0 0 83.33333%;
}
.col-lg-11
{
max-width: 91.66667%;
flex: 0 0 91.66667%;
}
.col-lg-12
{
max-width: 100%;
flex: 0 0 100%;
}
.order-lg-first
{
order: -1;
}
.order-lg-last
{
order: 13;
}
.order-lg-0
{
order: 0;
}
.order-lg-1
{
order: 1;
}
.order-lg-2
{
order: 2;
}
.order-lg-3
{
order: 3;
}
.order-lg-4
{
order: 4;
}
.order-lg-5
{
order: 5;
}
.order-lg-6
{
order: 6;
}
.order-lg-7
{
order: 7;
}
.order-lg-8
{
order: 8;
}
.order-lg-9
{
order: 9;
}
.order-lg-10
{
order: 10;
}
.order-lg-11
{
order: 11;
}
.order-lg-12
{
order: 12;
}
.offset-lg-0
{
margin-left: 0;
}
.offset-lg-1
{
margin-left: 8.33333%;
}
.offset-lg-2
{
margin-left: 16.66667%;
}
.offset-lg-3
{
margin-left: 25%;
}
.offset-lg-4
{
margin-left: 33.33333%;
}
.offset-lg-5
{
margin-left: 41.66667%;
}
.offset-lg-6
{
margin-left: 50%;
}
.offset-lg-7
{
margin-left: 58.33333%;
}
.offset-lg-8
{
margin-left: 66.66667%;
}
.offset-lg-9
{
margin-left: 75%;
}
.offset-lg-10
{
margin-left: 83.33333%;
}
.offset-lg-11
{
margin-left: 91.66667%;
}
}
@media (min-width: 1200px)
{
.col-xl
{
max-width: 100%;
flex-basis: 0;
flex-grow: 1;
}
.col-xl-auto
{
width: auto;
max-width: none;
flex: 0 0 auto;
}
.col-xl-1
{
max-width: 8.33333%;
flex: 0 0 8.33333%;
}
.col-xl-2
{
max-width: 16.66667%;
flex: 0 0 16.66667%;
}
.col-xl-3
{
max-width: 25%;
flex: 0 0 25%;
}
.col-xl-4
{
max-width: 33.33333%;
flex: 0 0 33.33333%;
}
.col-xl-5
{
max-width: 41.66667%;
flex: 0 0 41.66667%;
}
.col-xl-6
{
max-width: 50%;
flex: 0 0 50%;
}
.col-xl-7
{
max-width: 58.33333%;
flex: 0 0 58.33333%;
}
.col-xl-8
{
max-width: 66.66667%;
flex: 0 0 66.66667%;
}
.col-xl-9
{
max-width: 75%;
flex: 0 0 75%;
}
.col-xl-10
{
max-width: 83.33333%;
flex: 0 0 83.33333%;
}
.col-xl-11
{
max-width: 91.66667%;
flex: 0 0 91.66667%;
}
.col-xl-12
{
max-width: 100%;
flex: 0 0 100%;
}
.order-xl-first
{
order: -1;
}
.order-xl-last
{
order: 13;
}
.order-xl-0
{
order: 0;
}
.order-xl-1
{
order: 1;
}
.order-xl-2
{
order: 2;
}
.order-xl-3
{
order: 3;
}
.order-xl-4
{
order: 4;
}
.order-xl-5
{
order: 5;
}
.order-xl-6
{
order: 6;
}
.order-xl-7
{
order: 7;
}
.order-xl-8
{
order: 8;
}
.order-xl-9
{
order: 9;
}
.order-xl-10
{
order: 10;
}
.order-xl-11
{
order: 11;
}
.order-xl-12
{
order: 12;
}
.offset-xl-0
{
margin-left: 0;
}
.offset-xl-1
{
margin-left: 8.33333%;
}
.offset-xl-2
{
margin-left: 16.66667%;
}
.offset-xl-3
{
margin-left: 25%;
}
.offset-xl-4
{
margin-left: 33.33333%;
}
.offset-xl-5
{
margin-left: 41.66667%;
}
.offset-xl-6
{
margin-left: 50%;
}
.offset-xl-7
{
margin-left: 58.33333%;
}
.offset-xl-8
{
margin-left: 66.66667%;
}
.offset-xl-9
{
margin-left: 75%;
}
.offset-xl-10
{
margin-left: 83.33333%;
}
.offset-xl-11
{
margin-left: 91.66667%;
}
}
.table
{
width: 100%;
margin-bottom: 1rem;
background-color: transparent;
}
.table th,
.table td
{
padding: 1rem;
vertical-align: top;
border-top: 1px solid #e9ecef;
}
.table thead th
{
vertical-align: bottom;
border-bottom: 2px solid #e9ecef;
}
.table tbody + tbody
{
border-top: 2px solid #e9ecef;
}
.table .table
{
background-color: #f8f9fe;
}
.table-sm th,
.table-sm td
{
padding: .5rem;
}
.table-bordered
{
border: 1px solid #e9ecef;
}
.table-bordered th,
.table-bordered td
{
border: 1px solid #e9ecef;
}
.table-bordered thead th,
.table-bordered thead td
{
border-bottom-width: 2px;
}
.table-borderless th,
.table-borderless td,
.table-borderless thead th,
.table-borderless tbody + tbody
{
border: 0;
}
.table-striped tbody tr:nth-of-type(odd)
{
background-color: rgba(0, 0, 0, .05);
}
.table-hover tbody tr:hover
{
background-color: #f6f9fc;
}
.table-primary,
.table-primary > th,
.table-primary > td
{
background-color: #d2d8f7;
}
.table-hover .table-primary:hover
{
background-color: #bcc5f3;
}
.table-hover .table-primary:hover > td,
.table-hover .table-primary:hover > th
{
background-color: #bcc5f3;
}
.table-secondary,
.table-secondary > th,
.table-secondary > td
{
background-color: #fdfefe;
}
.table-hover .table-secondary:hover
{
background-color: #ecf6f6;
}
.table-hover .table-secondary:hover > td,
.table-hover .table-secondary:hover > th
{
background-color: #ecf6f6;
}
.table-success,
.table-success > th,
.table-success > td
{
background-color: #c4f1de;
}
.table-hover .table-success:hover
{
background-color: #afecd2;
}
.table-hover .table-success:hover > td,
.table-hover .table-success:hover > th
{
background-color: #afecd2;
}
.table-info,
.table-info > th,
.table-info > td
{
background-color: #bcf1fb;
}
.table-hover .table-info:hover
{
background-color: #a4ecfa;
}
.table-hover .table-info:hover > td,
.table-hover .table-info:hover > th
{
background-color: #a4ecfa;
}
.table-warning,
.table-warning > th,
.table-warning > td
{
background-color: #fed3ca;
}
.table-hover .table-warning:hover
{
background-color: #febeb1;
}
.table-hover .table-warning:hover > td,
.table-hover .table-warning:hover > th
{
background-color: #febeb1;
}
.table-danger,
.table-danger > th,
.table-danger > td
{
background-color: #fcc7d1;
}
.table-hover .table-danger:hover
{
background-color: #fbafbd;
}
.table-hover .table-danger:hover > td,
.table-hover .table-danger:hover > th
{
background-color: #fbafbd;
}
.table-light,
.table-light > th,
.table-light > td
{
background-color: #e8eaed;
}
.table-hover .table-light:hover
{
background-color: #dadde2;
}
.table-hover .table-light:hover > td,
.table-hover .table-light:hover > th
{
background-color: #dadde2;
}
.table-dark,
.table-dark > th,
.table-dark > td
{
background-color: #c1c2c3;
}
.table-hover .table-dark:hover
{
background-color: #b4b5b6;
}
.table-hover .table-dark:hover > td,
.table-hover .table-dark:hover > th
{
background-color: #b4b5b6;
}
.table-default,
.table-default > th,
.table-default > td
{
background-color: #bec4cd;
}
.table-hover .table-default:hover
{
background-color: #b0b7c2;
}
.table-hover .table-default:hover > td,
.table-hover .table-default:hover > th
{
background-color: #b0b7c2;
}
.table-white,
.table-white > th,
.table-white > td
{
background-color: white;
}
.table-hover .table-white:hover
{
background-color: #f2f2f2;
}
.table-hover .table-white:hover > td,
.table-hover .table-white:hover > th
{
background-color: #f2f2f2;
}
.table-neutral,
.table-neutral > th,
.table-neutral > td
{
background-color: white;
}
.table-hover .table-neutral:hover
{
background-color: #f2f2f2;
}
.table-hover .table-neutral:hover > td,
.table-hover .table-neutral:hover > th
{
background-color: #f2f2f2;
}
.table-darker,
.table-darker > th,
.table-darker > td
{
background-color: #b8b8b8;
}
.table-hover .table-darker:hover
{
background-color: #ababab;
}
.table-hover .table-darker:hover > td,
.table-hover .table-darker:hover > th
{
background-color: #ababab;
}
.table-active,
.table-active > th,
.table-active > td
{
background-color: #f6f9fc;
}
.table-hover .table-active:hover
{
background-color: #e3ecf6;
}
.table-hover .table-active:hover > td,
.table-hover .table-active:hover > th
{
background-color: #e3ecf6;
}
.table .thead-dark th
{
color: #f8f9fe;
border-color: #1f3a68;
background-color: #172b4d;
}
.table .thead-light th
{
color: #8898aa;
border-color: #e9ecef;
background-color: #f6f9fc;
}
.table-dark
{
color: #f8f9fe;
background-color: #172b4d;
}
.table-dark th,
.table-dark td,
.table-dark thead th
{
border-color: #1f3a68;
}
.table-dark.table-bordered
{
border: 0;
}
.table-dark.table-striped tbody tr:nth-of-type(odd)
{
background-color: rgba(255, 255, 255, .05);
}
.table-dark.table-hover tbody tr:hover
{
background-color: rgba(255, 255, 255, .075);
}
@media (max-width: 575.98px)
{
.table-responsive-sm
{
display: block;
overflow-x: auto;
width: 100%;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.table-responsive-sm > .table-bordered
{
border: 0;
}
}
@media (max-width: 767.98px)
{
.table-responsive-md
{
display: block;
overflow-x: auto;
width: 100%;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.table-responsive-md > .table-bordered
{
border: 0;
}
}
@media (max-width: 991.98px)
{
.table-responsive-lg
{
display: block;
overflow-x: auto;
width: 100%;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.table-responsive-lg > .table-bordered
{
border: 0;
}
}
@media (max-width: 1199.98px)
{
.table-responsive-xl
{
display: block;
overflow-x: auto;
width: 100%;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.table-responsive-xl > .table-bordered
{
border: 0;
}
}
.table-responsive
{
display: block;
overflow-x: auto;
width: 100%;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.table-responsive > .table-bordered
{
border: 0;
}
.form-control
{
font-size: 1rem;
line-height: 1.5;
display: block;
width: 100%;
height: calc(2.75rem + 2px);
padding: .625rem .75rem;
transition: all .2s cubic-bezier(.68, -.55, .265, 1.55);
color: #8898aa;
border: 1px solid #cad1d7;
border-radius: .375rem;
background-color: #fff;
background-clip: padding-box;
box-shadow: none;
}
@media screen and (prefers-reduced-motion: reduce)
{
.form-control
{
transition: none;
}
}
.form-control::-ms-expand
{
border: 0;
background-color: transparent;
}
.form-control:focus
{
color: #8898aa;
border-color: rgba(50, 151, 211, .25);
outline: 0;
background-color: #fff;
box-shadow: none, none;
}
.form-control:-ms-input-placeholder
{
opacity: 1;
color: #adb5bd;
}
.form-control::-ms-input-placeholder
{
opacity: 1;
color: #adb5bd;
}
.form-control::placeholder
{
opacity: 1;
color: #adb5bd;
}
.form-control:disabled,
.form-control[readonly]
{
opacity: 1;
background-color: #e9ecef;
}
select.form-control:focus::-ms-value
{
color: #8898aa;
background-color: #fff;
}
.form-control-file,
.form-control-range
{
display: block;
width: 100%;
}
.col-form-label
{
font-size: inherit;
line-height: 1.5;
margin-bottom: 0;
padding-top: calc(.625rem + 1px);
padding-bottom: calc(.625rem + 1px);
}
.col-form-label-lg
{
font-size: 1.25rem;
line-height: 1.5;
padding-top: calc(.875rem + 1px);
padding-bottom: calc(.875rem + 1px);
}
.col-form-label-sm
{
font-size: .875rem;
line-height: 1.5;
padding-top: calc(.25rem + 1px);
padding-bottom: calc(.25rem + 1px);
}
.form-control-plaintext
{
line-height: 1.5;
display: block;
width: 100%;
margin-bottom: 0;
padding-top: .625rem;
padding-bottom: .625rem;
color: #525f7f;
border: solid transparent;
border-width: 1px 0;
background-color: transparent;
}
.form-control-plaintext.form-control-sm,
.form-control-plaintext.form-control-lg
{
padding-right: 0;
padding-left: 0;
}
.form-control-sm
{
font-size: .875rem;
line-height: 1.5;
height: calc(1.8125rem + 2px);
padding: .25rem .5rem;
border-radius: .25rem;
}
.form-control-lg
{
font-size: 1.25rem;
line-height: 1.5;
height: calc(3.625rem + 2px);
padding: .875rem 1rem;
border-radius: .4375rem;
}
select.form-control[size],
select.form-control[multiple]
{
height: auto;
}
textarea.form-control
{
height: auto;
}
.form-group
{
margin-bottom: 1.5rem;
}
.form-text
{
display: block;
margin-top: .25rem;
}
.form-row
{
display: flex;
margin-right: -5px;
margin-left: -5px;
flex-wrap: wrap;
}
.form-row > .col,
.form-row > [class*='col-']
{
padding-right: 5px;
padding-left: 5px;
}
.form-check
{
position: relative;
display: block;
padding-left: 1.25rem;
}
.form-check-input
{
position: absolute;
margin-top: .3rem;
margin-left: -1.25rem;
}
.form-check-input:disabled ~ .form-check-label
{
color: #8898aa;
}
.form-check-label
{
margin-bottom: 0;
}
.form-check-inline
{
display: inline-flex;
margin-right: .75rem;
padding-left: 0;
align-items: center;
}
.form-check-inline .form-check-input
{
position: static;
margin-top: 0;
margin-right: .3125rem;
margin-left: 0;
}
.valid-feedback
{
font-size: 80%;
display: none;
width: 100%;
margin-top: .25rem;
color: #2dce89;
}
.valid-tooltip
{
font-size: .875rem;
line-height: 1;
position: absolute;
z-index: 5;
top: 100%;
display: none;
max-width: 100%;
margin-top: .1rem;
padding: .5rem;
color: #fff;
border-radius: .2rem;
background-color: rgba(45, 206, 137, .8);
}
.was-validated .form-control:valid,
.form-control.is-valid,
.was-validated
.custom-select:valid,
.custom-select.is-valid
{
border-color: #2dce89;
}
.was-validated .form-control:valid:focus,
.form-control.is-valid:focus,
.was-validated
.custom-select:valid:focus,
.custom-select.is-valid:focus
{
border-color: #2dce89;
}
.was-validated .form-control:valid ~ .valid-feedback,
.was-validated .form-control:valid ~ .valid-tooltip,
.form-control.is-valid ~ .valid-feedback,
.form-control.is-valid ~ .valid-tooltip,
.was-validated
.custom-select:valid ~ .valid-feedback,
.was-validated
.custom-select:valid ~ .valid-tooltip,
.custom-select.is-valid ~ .valid-feedback,
.custom-select.is-valid ~ .valid-tooltip
{
display: block;
}
.was-validated .form-check-input:valid ~ .form-check-label,
.form-check-input.is-valid ~ .form-check-label
{
color: #2dce89;
}
.was-validated .form-check-input:valid ~ .valid-feedback,
.was-validated .form-check-input:valid ~ .valid-tooltip,
.form-check-input.is-valid ~ .valid-feedback,
.form-check-input.is-valid ~ .valid-tooltip
{
display: block;
}
.was-validated .custom-control-input:valid ~ .custom-control-label,
.custom-control-input.is-valid ~ .custom-control-label
{
color: #2dce89;
}
.was-validated .custom-control-input:valid ~ .custom-control-label::before,
.custom-control-input.is-valid ~ .custom-control-label::before
{
border-color: #93e7c3;
background-color: #93e7c3;
}
.was-validated .custom-control-input:valid ~ .valid-feedback,
.was-validated .custom-control-input:valid ~ .valid-tooltip,
.custom-control-input.is-valid ~ .valid-feedback,
.custom-control-input.is-valid ~ .valid-tooltip
{
display: block;
}
.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before,
.custom-control-input.is-valid:checked ~ .custom-control-label::before
{
border-color: #93e7c3;
background-color: #54daa1;
}
.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before,
.custom-control-input.is-valid:focus ~ .custom-control-label::before
{
box-shadow: 0 0 0 1px #f8f9fe, 0 0 0 0 rgba(45, 206, 137, .25);
}
.was-validated .custom-file-input:valid ~ .custom-file-label,
.custom-file-input.is-valid ~ .custom-file-label
{
border-color: #2dce89;
}
.was-validated .custom-file-input:valid ~ .custom-file-label::before,
.custom-file-input.is-valid ~ .custom-file-label::before
{
border-color: inherit;
}
.was-validated .custom-file-input:valid ~ .valid-feedback,
.was-validated .custom-file-input:valid ~ .valid-tooltip,
.custom-file-input.is-valid ~ .valid-feedback,
.custom-file-input.is-valid ~ .valid-tooltip
{
display: block;
}
.was-validated .custom-file-input:valid:focus ~ .custom-file-label,
.custom-file-input.is-valid:focus ~ .custom-file-label
{
box-shadow: 0 0 0 0 rgba(45, 206, 137, .25);
}
.invalid-feedback
{
font-size: 80%;
display: none;
width: 100%;
margin-top: .25rem;
color: #fb6340;
}
.invalid-tooltip
{
font-size: .875rem;
line-height: 1;
position: absolute;
z-index: 5;
top: 100%;
display: none;
max-width: 100%;
margin-top: .1rem;
padding: .5rem;
color: #fff;
border-radius: .2rem;
background-color: rgba(251, 99, 64, .8);
}
.was-validated .form-control:invalid,
.form-control.is-invalid,
.was-validated
.custom-select:invalid,
.custom-select.is-invalid
{
border-color: #fb6340;
}
.was-validated .form-control:invalid:focus,
.form-control.is-invalid:focus,
.was-validated
.custom-select:invalid:focus,
.custom-select.is-invalid:focus
{
border-color: #fb6340;
}
.was-validated .form-control:invalid ~ .invalid-feedback,
.was-validated .form-control:invalid ~ .invalid-tooltip,
.form-control.is-invalid ~ .invalid-feedback,
.form-control.is-invalid ~ .invalid-tooltip,
.was-validated
.custom-select:invalid ~ .invalid-feedback,
.was-validated
.custom-select:invalid ~ .invalid-tooltip,
.custom-select.is-invalid ~ .invalid-feedback,
.custom-select.is-invalid ~ .invalid-tooltip
{
display: block;
}
.was-validated .form-check-input:invalid ~ .form-check-label,
.form-check-input.is-invalid ~ .form-check-label
{
color: #fb6340;
}
.was-validated .form-check-input:invalid ~ .invalid-feedback,
.was-validated .form-check-input:invalid ~ .invalid-tooltip,
.form-check-input.is-invalid ~ .invalid-feedback,
.form-check-input.is-invalid ~ .invalid-tooltip
{
display: block;
}
.was-validated .custom-control-input:invalid ~ .custom-control-label,
.custom-control-input.is-invalid ~ .custom-control-label
{
color: #fb6340;
}
.was-validated .custom-control-input:invalid ~ .custom-control-label::before,
.custom-control-input.is-invalid ~ .custom-control-label::before
{
border-color: #fec9bd;
background-color: #fec9bd;
}
.was-validated .custom-control-input:invalid ~ .invalid-feedback,
.was-validated .custom-control-input:invalid ~ .invalid-tooltip,
.custom-control-input.is-invalid ~ .invalid-feedback,
.custom-control-input.is-invalid ~ .invalid-tooltip
{
display: block;
}
.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before,
.custom-control-input.is-invalid:checked ~ .custom-control-label::before
{
border-color: #fec9bd;
background-color: #fc8c72;
}
.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before,
.custom-control-input.is-invalid:focus ~ .custom-control-label::before
{
box-shadow: 0 0 0 1px #f8f9fe, 0 0 0 0 rgba(251, 99, 64, .25);
}
.was-validated .custom-file-input:invalid ~ .custom-file-label,
.custom-file-input.is-invalid ~ .custom-file-label
{
border-color: #fb6340;
}
.was-validated .custom-file-input:invalid ~ .custom-file-label::before,
.custom-file-input.is-invalid ~ .custom-file-label::before
{
border-color: inherit;
}
.was-validated .custom-file-input:invalid ~ .invalid-feedback,
.was-validated .custom-file-input:invalid ~ .invalid-tooltip,
.custom-file-input.is-invalid ~ .invalid-feedback,
.custom-file-input.is-invalid ~ .invalid-tooltip
{
display: block;
}
.was-validated .custom-file-input:invalid:focus ~ .custom-file-label,
.custom-file-input.is-invalid:focus ~ .custom-file-label
{
box-shadow: 0 0 0 0 rgba(251, 99, 64, .25);
}
.form-inline
{
display: flex;
flex-flow: row wrap;
align-items: center;
}
.form-inline .form-check
{
width: 100%;
}
@media (min-width: 576px)
{
.form-inline label
{
display: flex;
margin-bottom: 0;
align-items: center;
justify-content: center;
}
.form-inline .form-group
{
display: flex;
margin-bottom: 0;
flex: 0 0 auto;
flex-flow: row wrap;
align-items: center;
}
.form-inline .form-control
{
display: inline-block;
width: auto;
vertical-align: middle;
}
.form-inline .form-control-plaintext
{
display: inline-block;
}
.form-inline .input-group,
.form-inline .custom-select
{
width: auto;
}
.form-inline .form-check
{
display: flex;
width: auto;
padding-left: 0;
align-items: center;
justify-content: center;
}
.form-inline .form-check-input
{
position: relative;
margin-top: 0;
margin-right: .25rem;
margin-left: 0;
}
.form-inline .custom-control
{
align-items: center;
justify-content: center;
}
.form-inline .custom-control-label
{
margin-bottom: 0;
}
}
.btn
{
font-size: 1rem;
font-weight: 600;
line-height: 1.5;
display: inline-block;
padding: .625rem 1.25rem;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
text-align: center;
vertical-align: middle;
white-space: nowrap;
border: 1px solid transparent;
border-radius: .375rem;
}
@media screen and (prefers-reduced-motion: reduce)
{
.btn
{
transition: none;
}
}
.btn:hover,
.btn:focus
{
text-decoration: none;
}
.btn:focus,
.btn.focus
{
outline: 0;
box-shadow: 0 7px 14px rgba(50, 50, 93, .1), 0 3px 6px rgba(0, 0, 0, .08);
}
.btn.disabled,
.btn:disabled
{
opacity: .65;
box-shadow: none;
}
.btn:not(:disabled):not(.disabled)
{
cursor: pointer;
}
.btn:not(:disabled):not(.disabled):active,
.btn:not(:disabled):not(.disabled).active
{
box-shadow: none;
}
.btn:not(:disabled):not(.disabled):active:focus,
.btn:not(:disabled):not(.disabled).active:focus
{
box-shadow: 0 7px 14px rgba(50, 50, 93, .1), 0 3px 6px rgba(0, 0, 0, .08), none;
}
a.btn.disabled,
fieldset:disabled a.btn
{
pointer-events: none;
}
.btn-primary
{
color: #fff;
border-color: #5e72e4;
background-color: #5e72e4;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-primary:hover
{
color: #fff;
border-color: #5e72e4;
background-color: #5e72e4;
}
.btn-primary:focus,
.btn-primary.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(94, 114, 228, .5);
}
.btn-primary.disabled,
.btn-primary:disabled
{
color: #fff;
border-color: #5e72e4;
background-color: #5e72e4;
}
.btn-primary:not(:disabled):not(.disabled):active,
.btn-primary:not(:disabled):not(.disabled).active,
.show > .btn-primary.dropdown-toggle
{
color: #fff;
border-color: #5e72e4;
background-color: #324cdd;
}
.btn-primary:not(:disabled):not(.disabled):active:focus,
.btn-primary:not(:disabled):not(.disabled).active:focus,
.show > .btn-primary.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(94, 114, 228, .5);
}
.btn-secondary
{
color: #212529;
border-color: #f7fafc;
background-color: #f7fafc;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-secondary:hover
{
color: #212529;
border-color: #f7fafc;
background-color: #f7fafc;
}
.btn-secondary:focus,
.btn-secondary.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(247, 250, 252, .5);
}
.btn-secondary.disabled,
.btn-secondary:disabled
{
color: #212529;
border-color: #f7fafc;
background-color: #f7fafc;
}
.btn-secondary:not(:disabled):not(.disabled):active,
.btn-secondary:not(:disabled):not(.disabled).active,
.show > .btn-secondary.dropdown-toggle
{
color: #212529;
border-color: #f7fafc;
background-color: #d2e3ee;
}
.btn-secondary:not(:disabled):not(.disabled):active:focus,
.btn-secondary:not(:disabled):not(.disabled).active:focus,
.show > .btn-secondary.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(247, 250, 252, .5);
}
.btn-success
{
color: #fff;
border-color: #2dce89;
background-color: #2dce89;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-success:hover
{
color: #fff;
border-color: #2dce89;
background-color: #2dce89;
}
.btn-success:focus,
.btn-success.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(45, 206, 137, .5);
}
.btn-success.disabled,
.btn-success:disabled
{
color: #fff;
border-color: #2dce89;
background-color: #2dce89;
}
.btn-success:not(:disabled):not(.disabled):active,
.btn-success:not(:disabled):not(.disabled).active,
.show > .btn-success.dropdown-toggle
{
color: #fff;
border-color: #2dce89;
background-color: #24a46d;
}
.btn-success:not(:disabled):not(.disabled):active:focus,
.btn-success:not(:disabled):not(.disabled).active:focus,
.show > .btn-success.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(45, 206, 137, .5);
}
.btn-info
{
color: #fff;
border-color: #11cdef;
background-color: #11cdef;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-info:hover
{
color: #fff;
border-color: #11cdef;
background-color: #11cdef;
}
.btn-info:focus,
.btn-info.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(17, 205, 239, .5);
}
.btn-info.disabled,
.btn-info:disabled
{
color: #fff;
border-color: #11cdef;
background-color: #11cdef;
}
.btn-info:not(:disabled):not(.disabled):active,
.btn-info:not(:disabled):not(.disabled).active,
.show > .btn-info.dropdown-toggle
{
color: #fff;
border-color: #11cdef;
background-color: #0da5c0;
}
.btn-info:not(:disabled):not(.disabled):active:focus,
.btn-info:not(:disabled):not(.disabled).active:focus,
.show > .btn-info.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(17, 205, 239, .5);
}
.btn-warning
{
color: #fff;
border-color: #fb6340;
background-color: #fb6340;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-warning:hover
{
color: #fff;
border-color: #fb6340;
background-color: #fb6340;
}
.btn-warning:focus,
.btn-warning.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(251, 99, 64, .5);
}
.btn-warning.disabled,
.btn-warning:disabled
{
color: #fff;
border-color: #fb6340;
background-color: #fb6340;
}
.btn-warning:not(:disabled):not(.disabled):active,
.btn-warning:not(:disabled):not(.disabled).active,
.show > .btn-warning.dropdown-toggle
{
color: #fff;
border-color: #fb6340;
background-color: #fa3a0e;
}
.btn-warning:not(:disabled):not(.disabled):active:focus,
.btn-warning:not(:disabled):not(.disabled).active:focus,
.show > .btn-warning.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(251, 99, 64, .5);
}
.btn-danger
{
color: #fff;
border-color: #f5365c;
background-color: #f5365c;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-danger:hover
{
color: #fff;
border-color: #f5365c;
background-color: #f5365c;
}
.btn-danger:focus,
.btn-danger.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(245, 54, 92, .5);
}
.btn-danger.disabled,
.btn-danger:disabled
{
color: #fff;
border-color: #f5365c;
background-color: #f5365c;
}
.btn-danger:not(:disabled):not(.disabled):active,
.btn-danger:not(:disabled):not(.disabled).active,
.show > .btn-danger.dropdown-toggle
{
color: #fff;
border-color: #f5365c;
background-color: #ec0c38;
}
.btn-danger:not(:disabled):not(.disabled):active:focus,
.btn-danger:not(:disabled):not(.disabled).active:focus,
.show > .btn-danger.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(245, 54, 92, .5);
}
.btn-light
{
color: #fff;
border-color: #adb5bd;
background-color: #adb5bd;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-light:hover
{
color: #fff;
border-color: #adb5bd;
background-color: #adb5bd;
}
.btn-light:focus,
.btn-light.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(173, 181, 189, .5);
}
.btn-light.disabled,
.btn-light:disabled
{
color: #fff;
border-color: #adb5bd;
background-color: #adb5bd;
}
.btn-light:not(:disabled):not(.disabled):active,
.btn-light:not(:disabled):not(.disabled).active,
.show > .btn-light.dropdown-toggle
{
color: #fff;
border-color: #adb5bd;
background-color: #919ca6;
}
.btn-light:not(:disabled):not(.disabled):active:focus,
.btn-light:not(:disabled):not(.disabled).active:focus,
.show > .btn-light.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(173, 181, 189, .5);
}
.btn-dark
{
color: #fff;
border-color: #212529;
background-color: #212529;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-dark:hover
{
color: #fff;
border-color: #212529;
background-color: #212529;
}
.btn-dark:focus,
.btn-dark.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(33, 37, 41, .5);
}
.btn-dark.disabled,
.btn-dark:disabled
{
color: #fff;
border-color: #212529;
background-color: #212529;
}
.btn-dark:not(:disabled):not(.disabled):active,
.btn-dark:not(:disabled):not(.disabled).active,
.show > .btn-dark.dropdown-toggle
{
color: #fff;
border-color: #212529;
background-color: #0a0c0d;
}
.btn-dark:not(:disabled):not(.disabled):active:focus,
.btn-dark:not(:disabled):not(.disabled).active:focus,
.show > .btn-dark.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(33, 37, 41, .5);
}
.btn-default
{
color: #fff;
border-color: #172b4d;
background-color: #172b4d;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-default:hover
{
color: #fff;
border-color: #172b4d;
background-color: #172b4d;
}
.btn-default:focus,
.btn-default.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(23, 43, 77, .5);
}
.btn-default.disabled,
.btn-default:disabled
{
color: #fff;
border-color: #172b4d;
background-color: #172b4d;
}
.btn-default:not(:disabled):not(.disabled):active,
.btn-default:not(:disabled):not(.disabled).active,
.show > .btn-default.dropdown-toggle
{
color: #fff;
border-color: #172b4d;
background-color: #0b1526;
}
.btn-default:not(:disabled):not(.disabled):active:focus,
.btn-default:not(:disabled):not(.disabled).active:focus,
.show > .btn-default.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(23, 43, 77, .5);
}
.btn-white
{
color: #212529;
border-color: #fff;
background-color: #fff;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-white:hover
{
color: #212529;
border-color: white;
background-color: white;
}
.btn-white:focus,
.btn-white.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(255, 255, 255, .5);
}
.btn-white.disabled,
.btn-white:disabled
{
color: #212529;
border-color: #fff;
background-color: #fff;
}
.btn-white:not(:disabled):not(.disabled):active,
.btn-white:not(:disabled):not(.disabled).active,
.show > .btn-white.dropdown-toggle
{
color: #212529;
border-color: white;
background-color: #e6e6e6;
}
.btn-white:not(:disabled):not(.disabled):active:focus,
.btn-white:not(:disabled):not(.disabled).active:focus,
.show > .btn-white.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(255, 255, 255, .5);
}
.btn-neutral
{
color: #212529;
border-color: #fff;
background-color: #fff;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-neutral:hover
{
color: #212529;
border-color: white;
background-color: white;
}
.btn-neutral:focus,
.btn-neutral.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(255, 255, 255, .5);
}
.btn-neutral.disabled,
.btn-neutral:disabled
{
color: #212529;
border-color: #fff;
background-color: #fff;
}
.btn-neutral:not(:disabled):not(.disabled):active,
.btn-neutral:not(:disabled):not(.disabled).active,
.show > .btn-neutral.dropdown-toggle
{
color: #212529;
border-color: white;
background-color: #e6e6e6;
}
.btn-neutral:not(:disabled):not(.disabled):active:focus,
.btn-neutral:not(:disabled):not(.disabled).active:focus,
.show > .btn-neutral.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(255, 255, 255, .5);
}
.btn-darker
{
color: #fff;
border-color: black;
background-color: black;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-darker:hover
{
color: #fff;
border-color: black;
background-color: black;
}
.btn-darker:focus,
.btn-darker.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(0, 0, 0, .5);
}
.btn-darker.disabled,
.btn-darker:disabled
{
color: #fff;
border-color: black;
background-color: black;
}
.btn-darker:not(:disabled):not(.disabled):active,
.btn-darker:not(:disabled):not(.disabled).active,
.show > .btn-darker.dropdown-toggle
{
color: #fff;
border-color: black;
background-color: black;
}
.btn-darker:not(:disabled):not(.disabled):active:focus,
.btn-darker:not(:disabled):not(.disabled).active:focus,
.show > .btn-darker.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(0, 0, 0, .5);
}
.btn-outline-primary
{
color: #5e72e4;
border-color: #5e72e4;
background-color: transparent;
background-image: none;
}
.btn-outline-primary:hover
{
color: #fff;
border-color: #5e72e4;
background-color: #5e72e4;
}
.btn-outline-primary:focus,
.btn-outline-primary.focus
{
box-shadow: 0 0 0 0 rgba(94, 114, 228, .5);
}
.btn-outline-primary.disabled,
.btn-outline-primary:disabled
{
color: #5e72e4;
background-color: transparent;
}
.btn-outline-primary:not(:disabled):not(.disabled):active,
.btn-outline-primary:not(:disabled):not(.disabled).active,
.show > .btn-outline-primary.dropdown-toggle
{
color: #fff;
border-color: #5e72e4;
background-color: #5e72e4;
}
.btn-outline-primary:not(:disabled):not(.disabled):active:focus,
.btn-outline-primary:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-primary.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(94, 114, 228, .5);
}
.btn-outline-secondary
{
color: #f7fafc;
border-color: #f7fafc;
background-color: transparent;
background-image: none;
}
.btn-outline-secondary:hover
{
color: #212529;
border-color: #f7fafc;
background-color: #f7fafc;
}
.btn-outline-secondary:focus,
.btn-outline-secondary.focus
{
box-shadow: 0 0 0 0 rgba(247, 250, 252, .5);
}
.btn-outline-secondary.disabled,
.btn-outline-secondary:disabled
{
color: #f7fafc;
background-color: transparent;
}
.btn-outline-secondary:not(:disabled):not(.disabled):active,
.btn-outline-secondary:not(:disabled):not(.disabled).active,
.show > .btn-outline-secondary.dropdown-toggle
{
color: #212529;
border-color: #f7fafc;
background-color: #f7fafc;
}
.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,
.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-secondary.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(247, 250, 252, .5);
}
.btn-outline-success
{
color: #2dce89;
border-color: #2dce89;
background-color: transparent;
background-image: none;
}
.btn-outline-success:hover
{
color: #fff;
border-color: #2dce89;
background-color: #2dce89;
}
.btn-outline-success:focus,
.btn-outline-success.focus
{
box-shadow: 0 0 0 0 rgba(45, 206, 137, .5);
}
.btn-outline-success.disabled,
.btn-outline-success:disabled
{
color: #2dce89;
background-color: transparent;
}
.btn-outline-success:not(:disabled):not(.disabled):active,
.btn-outline-success:not(:disabled):not(.disabled).active,
.show > .btn-outline-success.dropdown-toggle
{
color: #fff;
border-color: #2dce89;
background-color: #2dce89;
}
.btn-outline-success:not(:disabled):not(.disabled):active:focus,
.btn-outline-success:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-success.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(45, 206, 137, .5);
}
.btn-outline-info
{
color: #11cdef;
border-color: #11cdef;
background-color: transparent;
background-image: none;
}
.btn-outline-info:hover
{
color: #fff;
border-color: #11cdef;
background-color: #11cdef;
}
.btn-outline-info:focus,
.btn-outline-info.focus
{
box-shadow: 0 0 0 0 rgba(17, 205, 239, .5);
}
.btn-outline-info.disabled,
.btn-outline-info:disabled
{
color: #11cdef;
background-color: transparent;
}
.btn-outline-info:not(:disabled):not(.disabled):active,
.btn-outline-info:not(:disabled):not(.disabled).active,
.show > .btn-outline-info.dropdown-toggle
{
color: #fff;
border-color: #11cdef;
background-color: #11cdef;
}
.btn-outline-info:not(:disabled):not(.disabled):active:focus,
.btn-outline-info:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-info.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(17, 205, 239, .5);
}
.btn-outline-warning
{
color: #fb6340;
border-color: #fb6340;
background-color: transparent;
background-image: none;
}
.btn-outline-warning:hover
{
color: #fff;
border-color: #fb6340;
background-color: #fb6340;
}
.btn-outline-warning:focus,
.btn-outline-warning.focus
{
box-shadow: 0 0 0 0 rgba(251, 99, 64, .5);
}
.btn-outline-warning.disabled,
.btn-outline-warning:disabled
{
color: #fb6340;
background-color: transparent;
}
.btn-outline-warning:not(:disabled):not(.disabled):active,
.btn-outline-warning:not(:disabled):not(.disabled).active,
.show > .btn-outline-warning.dropdown-toggle
{
color: #fff;
border-color: #fb6340;
background-color: #fb6340;
}
.btn-outline-warning:not(:disabled):not(.disabled):active:focus,
.btn-outline-warning:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-warning.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(251, 99, 64, .5);
}
.btn-outline-danger
{
color: #f5365c;
border-color: #f5365c;
background-color: transparent;
background-image: none;
}
.btn-outline-danger:hover
{
color: #fff;
border-color: #f5365c;
background-color: #f5365c;
}
.btn-outline-danger:focus,
.btn-outline-danger.focus
{
box-shadow: 0 0 0 0 rgba(245, 54, 92, .5);
}
.btn-outline-danger.disabled,
.btn-outline-danger:disabled
{
color: #f5365c;
background-color: transparent;
}
.btn-outline-danger:not(:disabled):not(.disabled):active,
.btn-outline-danger:not(:disabled):not(.disabled).active,
.show > .btn-outline-danger.dropdown-toggle
{
color: #fff;
border-color: #f5365c;
background-color: #f5365c;
}
.btn-outline-danger:not(:disabled):not(.disabled):active:focus,
.btn-outline-danger:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-danger.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(245, 54, 92, .5);
}
.btn-outline-light
{
color: #adb5bd;
border-color: #adb5bd;
background-color: transparent;
background-image: none;
}
.btn-outline-light:hover
{
color: #fff;
border-color: #adb5bd;
background-color: #adb5bd;
}
.btn-outline-light:focus,
.btn-outline-light.focus
{
box-shadow: 0 0 0 0 rgba(173, 181, 189, .5);
}
.btn-outline-light.disabled,
.btn-outline-light:disabled
{
color: #adb5bd;
background-color: transparent;
}
.btn-outline-light:not(:disabled):not(.disabled):active,
.btn-outline-light:not(:disabled):not(.disabled).active,
.show > .btn-outline-light.dropdown-toggle
{
color: #fff;
border-color: #adb5bd;
background-color: #adb5bd;
}
.btn-outline-light:not(:disabled):not(.disabled):active:focus,
.btn-outline-light:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-light.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(173, 181, 189, .5);
}
.btn-outline-dark
{
color: #212529;
border-color: #212529;
background-color: transparent;
background-image: none;
}
.btn-outline-dark:hover
{
color: #fff;
border-color: #212529;
background-color: #212529;
}
.btn-outline-dark:focus,
.btn-outline-dark.focus
{
box-shadow: 0 0 0 0 rgba(33, 37, 41, .5);
}
.btn-outline-dark.disabled,
.btn-outline-dark:disabled
{
color: #212529;
background-color: transparent;
}
.btn-outline-dark:not(:disabled):not(.disabled):active,
.btn-outline-dark:not(:disabled):not(.disabled).active,
.show > .btn-outline-dark.dropdown-toggle
{
color: #fff;
border-color: #212529;
background-color: #212529;
}
.btn-outline-dark:not(:disabled):not(.disabled):active:focus,
.btn-outline-dark:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-dark.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(33, 37, 41, .5);
}
.btn-outline-default
{
color: #172b4d;
border-color: #172b4d;
background-color: transparent;
background-image: none;
}
.btn-outline-default:hover
{
color: #fff;
border-color: #172b4d;
background-color: #172b4d;
}
.btn-outline-default:focus,
.btn-outline-default.focus
{
box-shadow: 0 0 0 0 rgba(23, 43, 77, .5);
}
.btn-outline-default.disabled,
.btn-outline-default:disabled
{
color: #172b4d;
background-color: transparent;
}
.btn-outline-default:not(:disabled):not(.disabled):active,
.btn-outline-default:not(:disabled):not(.disabled).active,
.show > .btn-outline-default.dropdown-toggle
{
color: #fff;
border-color: #172b4d;
background-color: #172b4d;
}
.btn-outline-default:not(:disabled):not(.disabled):active:focus,
.btn-outline-default:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-default.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(23, 43, 77, .5);
}
.btn-outline-white
{
color: #fff;
border-color: #fff;
background-color: transparent;
background-image: none;
}
.btn-outline-white:hover
{
color: #212529;
border-color: #fff;
background-color: #fff;
}
.btn-outline-white:focus,
.btn-outline-white.focus
{
box-shadow: 0 0 0 0 rgba(255, 255, 255, .5);
}
.btn-outline-white.disabled,
.btn-outline-white:disabled
{
color: #fff;
background-color: transparent;
}
.btn-outline-white:not(:disabled):not(.disabled):active,
.btn-outline-white:not(:disabled):not(.disabled).active,
.show > .btn-outline-white.dropdown-toggle
{
color: #212529;
border-color: #fff;
background-color: #fff;
}
.btn-outline-white:not(:disabled):not(.disabled):active:focus,
.btn-outline-white:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-white.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(255, 255, 255, .5);
}
.btn-outline-neutral
{
color: #fff;
border-color: #fff;
background-color: transparent;
background-image: none;
}
.btn-outline-neutral:hover
{
color: #212529;
border-color: #fff;
background-color: #fff;
}
.btn-outline-neutral:focus,
.btn-outline-neutral.focus
{
box-shadow: 0 0 0 0 rgba(255, 255, 255, .5);
}
.btn-outline-neutral.disabled,
.btn-outline-neutral:disabled
{
color: #fff;
background-color: transparent;
}
.btn-outline-neutral:not(:disabled):not(.disabled):active,
.btn-outline-neutral:not(:disabled):not(.disabled).active,
.show > .btn-outline-neutral.dropdown-toggle
{
color: #212529;
border-color: #fff;
background-color: #fff;
}
.btn-outline-neutral:not(:disabled):not(.disabled):active:focus,
.btn-outline-neutral:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-neutral.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(255, 255, 255, .5);
}
.btn-outline-darker
{
color: black;
border-color: black;
background-color: transparent;
background-image: none;
}
.btn-outline-darker:hover
{
color: #fff;
border-color: black;
background-color: black;
}
.btn-outline-darker:focus,
.btn-outline-darker.focus
{
box-shadow: 0 0 0 0 rgba(0, 0, 0, .5);
}
.btn-outline-darker.disabled,
.btn-outline-darker:disabled
{
color: black;
background-color: transparent;
}
.btn-outline-darker:not(:disabled):not(.disabled):active,
.btn-outline-darker:not(:disabled):not(.disabled).active,
.show > .btn-outline-darker.dropdown-toggle
{
color: #fff;
border-color: black;
background-color: black;
}
.btn-outline-darker:not(:disabled):not(.disabled):active:focus,
.btn-outline-darker:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-darker.dropdown-toggle:focus
{
box-shadow: 0 0 0 0 rgba(0, 0, 0, .5);
}
.btn-link
{
font-weight: 400;
color: #5e72e4;
background-color: transparent;
}
.btn-link:hover
{
text-decoration: none;
color: #233dd2;
border-color: transparent;
background-color: transparent;
}
.btn-link:focus,
.btn-link.focus
{
text-decoration: none;
border-color: transparent;
box-shadow: none;
}
.btn-link:disabled,
.btn-link.disabled
{
pointer-events: none;
color: #8898aa;
}
.btn-lg,
.btn-group-lg > .btn
{
font-size: 1.25rem;
line-height: 1.5;
padding: .875rem 1rem;
border-radius: .4375rem;
}
.btn-sm,
.btn-group-sm > .btn
{
font-size: .875rem;
line-height: 1.5;
padding: .25rem .5rem;
border-radius: .375rem;
}
.btn-block
{
display: block;
width: 100%;
}
.btn-block + .btn-block
{
margin-top: .5rem;
}
input[type='submit'].btn-block,
input[type='reset'].btn-block,
input[type='button'].btn-block
{
width: 100%;
}
.fade
{
transition: opacity .15s linear;
}
@media screen and (prefers-reduced-motion: reduce)
{
.fade
{
transition: none;
}
}
.fade:not(.show)
{
opacity: 0;
}
.collapse:not(.show)
{
display: none;
}
.collapsing
{
position: relative;
overflow: hidden;
height: 0;
transition: height .35s ease;
}
@media screen and (prefers-reduced-motion: reduce)
{
.collapsing
{
transition: none;
}
}
.dropup,
.dropright,
.dropdown,
.dropleft
{
position: relative;
}
.dropdown-toggle::after
{
display: inline-block;
width: 0;
height: 0;
margin-left: .255em;
content: '';
vertical-align: .255em;
border-top: .3em solid;
border-right: .3em solid transparent;
border-bottom: 0;
border-left: .3em solid transparent;
}
.dropdown-toggle:empty::after
{
margin-left: 0;
}
.dropdown-menu
{
font-size: 1rem;
position: absolute;
z-index: 1000;
top: 100%;
left: 0;
display: none;
float: left;
min-width: 10rem;
margin: .125rem 0 0;
padding: .5rem 0;
list-style: none;
text-align: left;
color: #525f7f;
border: 0 solid rgba(0, 0, 0, .15);
border-radius: .4375rem;
background-color: #fff;
background-clip: padding-box;
box-shadow: 0 50px 100px rgba(50, 50, 93, .1), 0 15px 35px rgba(50, 50, 93, .15), 0 5px 15px rgba(0, 0, 0, .1);
}
.dropdown-menu-right
{
right: 0;
left: auto;
}
.dropup .dropdown-menu
{
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: .125rem;
}
.dropup .dropdown-toggle::after
{
display: inline-block;
width: 0;
height: 0;
margin-left: .255em;
content: '';
vertical-align: .255em;
border-top: 0;
border-right: .3em solid transparent;
border-bottom: .3em solid;
border-left: .3em solid transparent;
}
.dropup .dropdown-toggle:empty::after
{
margin-left: 0;
}
.dropright .dropdown-menu
{
top: 0;
right: auto;
left: 100%;
margin-top: 0;
margin-left: .125rem;
}
.dropright .dropdown-toggle::after
{
display: inline-block;
width: 0;
height: 0;
margin-left: .255em;
content: '';
vertical-align: .255em;
border-top: .3em solid transparent;
border-right: 0;
border-bottom: .3em solid transparent;
border-left: .3em solid;
}
.dropright .dropdown-toggle:empty::after
{
margin-left: 0;
}
.dropright .dropdown-toggle::after
{
vertical-align: 0;
}
.dropleft .dropdown-menu
{
top: 0;
right: 100%;
left: auto;
margin-top: 0;
margin-right: .125rem;
}
.dropleft .dropdown-toggle::after
{
display: inline-block;
width: 0;
height: 0;
margin-left: .255em;
content: '';
vertical-align: .255em;
}
.dropleft .dropdown-toggle::after
{
display: none;
}
.dropleft .dropdown-toggle::before
{
display: inline-block;
width: 0;
height: 0;
margin-right: .255em;
content: '';
vertical-align: .255em;
border-top: .3em solid transparent;
border-right: .3em solid;
border-bottom: .3em solid transparent;
}
.dropleft .dropdown-toggle:empty::after
{
margin-left: 0;
}
.dropleft .dropdown-toggle::before
{
vertical-align: 0;
}
.dropdown-menu[x-placement^='top'],
.dropdown-menu[x-placement^='right'],
.dropdown-menu[x-placement^='bottom'],
.dropdown-menu[x-placement^='left']
{
right: auto;
bottom: auto;
}
.dropdown-divider
{
overflow: hidden;
height: 0;
margin: .5rem 0;
border-top: 1px solid #e9ecef;
}
.dropdown-item
{
font-weight: 400;
display: block;
clear: both;
width: 100%;
padding: .25rem 1.5rem;
text-align: inherit;
white-space: nowrap;
color: #212529;
border: 0;
background-color: transparent;
}
.dropdown-item:hover,
.dropdown-item:focus
{
text-decoration: none;
color: #16181b;
background-color: #f6f9fc;
}
.dropdown-item.active,
.dropdown-item:active
{
text-decoration: none;
color: #fff;
background-color: #5e72e4;
}
.dropdown-item.disabled,
.dropdown-item:disabled
{
color: #8898aa;
background-color: transparent;
}
.dropdown-menu.show
{
display: block;
}
.dropdown-header
{
font-size: .875rem;
display: block;
margin-bottom: 0;
padding: .5rem 1.5rem;
white-space: nowrap;
color: #8898aa;
}
.dropdown-item-text
{
display: block;
padding: .25rem 1.5rem;
color: #212529;
}
.btn-group,
.btn-group-vertical
{
position: relative;
display: inline-flex;
vertical-align: middle;
}
.btn-group > .btn,
.btn-group-vertical > .btn
{
position: relative;
flex: 0 1 auto;
}
.btn-group > .btn:hover,
.btn-group-vertical > .btn:hover
{
z-index: 1;
}
.btn-group > .btn:focus,
.btn-group > .btn:active,
.btn-group > .btn.active,
.btn-group-vertical > .btn:focus,
.btn-group-vertical > .btn:active,
.btn-group-vertical > .btn.active
{
z-index: 1;
}
.btn-group .btn + .btn,
.btn-group .btn + .btn-group,
.btn-group .btn-group + .btn,
.btn-group .btn-group + .btn-group,
.btn-group-vertical .btn + .btn,
.btn-group-vertical .btn + .btn-group,
.btn-group-vertical .btn-group + .btn,
.btn-group-vertical .btn-group + .btn-group
{
margin-left: -1px;
}
.btn-toolbar
{
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.btn-toolbar .input-group
{
width: auto;
}
.btn-group > .btn:first-child
{
margin-left: 0;
}
.btn-group > .btn:not(:last-child):not(.dropdown-toggle),
.btn-group > .btn-group:not(:last-child) > .btn
{
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.btn-group > .btn:not(:first-child),
.btn-group > .btn-group:not(:first-child) > .btn
{
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.dropdown-toggle-split
{
padding-right: .9375rem;
padding-left: .9375rem;
}
.dropdown-toggle-split::after,
.dropup .dropdown-toggle-split::after,
.dropright .dropdown-toggle-split::after
{
margin-left: 0;
}
.dropleft .dropdown-toggle-split::before
{
margin-right: 0;
}
.btn-sm + .dropdown-toggle-split,
.btn-group-sm > .btn + .dropdown-toggle-split
{
padding-right: .375rem;
padding-left: .375rem;
}
.btn-lg + .dropdown-toggle-split,
.btn-group-lg > .btn + .dropdown-toggle-split
{
padding-right: .75rem;
padding-left: .75rem;
}
.btn-group.show .dropdown-toggle
{
box-shadow: none;
}
.btn-group.show .dropdown-toggle.btn-link
{
box-shadow: none;
}
.btn-group-vertical
{
flex-direction: column;
align-items: flex-start;
justify-content: center;
}
.btn-group-vertical .btn,
.btn-group-vertical .btn-group
{
width: 100%;
}
.btn-group-vertical > .btn + .btn,
.btn-group-vertical > .btn + .btn-group,
.btn-group-vertical > .btn-group + .btn,
.btn-group-vertical > .btn-group + .btn-group
{
margin-top: -1px;
margin-left: 0;
}
.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),
.btn-group-vertical > .btn-group:not(:last-child) > .btn
{
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.btn-group-vertical > .btn:not(:first-child),
.btn-group-vertical > .btn-group:not(:first-child) > .btn
{
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.btn-group-toggle > .btn,
.btn-group-toggle > .btn-group > .btn
{
margin-bottom: 0;
}
.btn-group-toggle > .btn input[type='radio'],
.btn-group-toggle > .btn input[type='checkbox'],
.btn-group-toggle > .btn-group > .btn input[type='radio'],
.btn-group-toggle > .btn-group > .btn input[type='checkbox']
{
position: absolute;
clip: rect(0, 0, 0, 0);
pointer-events: none;
}
.input-group
{
position: relative;
display: flex;
width: 100%;
flex-wrap: wrap;
align-items: stretch;
}
.input-group > .form-control,
.input-group > .custom-select,
.input-group > .custom-file
{
position: relative;
width: 1%;
margin-bottom: 0;
flex: 1 1 auto;
}
.input-group > .form-control + .form-control,
.input-group > .form-control + .custom-select,
.input-group > .form-control + .custom-file,
.input-group > .custom-select + .form-control,
.input-group > .custom-select + .custom-select,
.input-group > .custom-select + .custom-file,
.input-group > .custom-file + .form-control,
.input-group > .custom-file + .custom-select,
.input-group > .custom-file + .custom-file
{
margin-left: -1px;
}
.input-group > .form-control:focus,
.input-group > .custom-select:focus,
.input-group > .custom-file .custom-file-input:focus ~ .custom-file-label
{
z-index: 3;
}
.input-group > .custom-file .custom-file-input:focus
{
z-index: 4;
}
.input-group > .form-control:not(:last-child),
.input-group > .custom-select:not(:last-child)
{
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group > .form-control:not(:first-child),
.input-group > .custom-select:not(:first-child)
{
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.input-group > .custom-file
{
display: flex;
align-items: center;
}
.input-group > .custom-file:not(:last-child) .custom-file-label,
.input-group > .custom-file:not(:last-child) .custom-file-label::after
{
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group > .custom-file:not(:first-child) .custom-file-label
{
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.input-group-prepend,
.input-group-append
{
display: flex;
}
.input-group-prepend .btn,
.input-group-append .btn
{
position: relative;
z-index: 2;
}
.input-group-prepend .btn + .btn,
.input-group-prepend .btn + .input-group-text,
.input-group-prepend .input-group-text + .input-group-text,
.input-group-prepend .input-group-text + .btn,
.input-group-append .btn + .btn,
.input-group-append .btn + .input-group-text,
.input-group-append .input-group-text + .input-group-text,
.input-group-append .input-group-text + .btn
{
margin-left: -1px;
}
.input-group-prepend
{
margin-right: -1px;
}
.input-group-append
{
margin-left: -1px;
}
.input-group-text
{
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
display: flex;
margin-bottom: 0;
padding: .625rem .75rem;
text-align: center;
white-space: nowrap;
color: #adb5bd;
border: 1px solid #cad1d7;
border-radius: .375rem;
background-color: #fff;
align-items: center;
}
.input-group-text input[type='radio'],
.input-group-text input[type='checkbox']
{
margin-top: 0;
}
.input-group-lg > .form-control,
.input-group-lg > .input-group-prepend > .input-group-text,
.input-group-lg > .input-group-append > .input-group-text,
.input-group-lg > .input-group-prepend > .btn,
.input-group-lg > .input-group-append > .btn
{
font-size: 1.25rem;
line-height: 1.5;
height: calc(3.625rem + 2px);
padding: .875rem 1rem;
border-radius: .4375rem;
}
.input-group-sm > .form-control,
.input-group-sm > .input-group-prepend > .input-group-text,
.input-group-sm > .input-group-append > .input-group-text,
.input-group-sm > .input-group-prepend > .btn,
.input-group-sm > .input-group-append > .btn
{
font-size: .875rem;
line-height: 1.5;
height: calc(1.8125rem + 2px);
padding: .25rem .5rem;
border-radius: .25rem;
}
.input-group > .input-group-prepend > .btn,
.input-group > .input-group-prepend > .input-group-text,
.input-group > .input-group-append:not(:last-child) > .btn,
.input-group > .input-group-append:not(:last-child) > .input-group-text,
.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle),
.input-group > .input-group-append:last-child > .input-group-text:not(:last-child)
{
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group > .input-group-append > .btn,
.input-group > .input-group-append > .input-group-text,
.input-group > .input-group-prepend:not(:first-child) > .btn,
.input-group > .input-group-prepend:not(:first-child) > .input-group-text,
.input-group > .input-group-prepend:first-child > .btn:not(:first-child),
.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child)
{
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.custom-control
{
position: relative;
display: block;
min-height: 1.5rem;
padding-left: 1.75rem;
}
.custom-control-inline
{
display: inline-flex;
margin-right: 1rem;
}
.custom-control-input
{
position: absolute;
z-index: -1;
opacity: 0;
}
.custom-control-input:checked ~ .custom-control-label::before
{
color: #fff;
background-color: #5e72e4;
box-shadow: none;
}
.custom-control-input:focus ~ .custom-control-label::before
{
box-shadow: none;
}
.custom-control-input:active ~ .custom-control-label::before
{
color: #fff;
background-color: #5e72e4;
box-shadow: none;
}
.custom-control-input:disabled ~ .custom-control-label
{
color: #8898aa;
}
.custom-control-input:disabled ~ .custom-control-label::before
{
background-color: #e9ecef;
}
.custom-control-label
{
position: relative;
margin-bottom: 0;
}
.custom-control-label::before
{
position: absolute;
top: .125rem;
left: -1.75rem;
display: block;
width: 1.25rem;
height: 1.25rem;
content: '';
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
background-color: #fff;
box-shadow: none;
}
.custom-control-label::after
{
position: absolute;
top: .125rem;
left: -1.75rem;
display: block;
width: 1.25rem;
height: 1.25rem;
content: '';
background-repeat: no-repeat;
background-position: center center;
background-size: 50% 50%;
}
.custom-checkbox .custom-control-label::before
{
border-radius: .25rem;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before
{
background-color: #5e72e4;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after
{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 8 8\'%3E%3Cpath fill=\'%23fff\' d=\'M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z\'/%3E%3C/svg%3E');
}
.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before
{
background-color: #5e72e4;
box-shadow: none;
}
.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after
{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 4 4\'%3E%3Cpath stroke=\'%23fff\' d=\'M0 2h4\'/%3E%3C/svg%3E');
}
.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before
{
background-color: rgba(94, 114, 228, .5);
}
.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before
{
background-color: rgba(94, 114, 228, .5);
}
.custom-radio .custom-control-label::before
{
border-radius: 50%;
}
.custom-radio .custom-control-input:checked ~ .custom-control-label::before
{
background-color: #5e72e4;
}
.custom-radio .custom-control-input:checked ~ .custom-control-label::after
{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'-4 -4 8 8\'%3E%3Ccircle r=\'3\' fill=\'%23fff\'/%3E%3C/svg%3E');
}
.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before
{
background-color: rgba(94, 114, 228, .5);
}
.custom-select
{
line-height: 1.5;
display: inline-block;
width: 100%;
height: calc(2.75rem + 2px);
padding: .375rem 1.75rem .375rem .75rem;
vertical-align: middle;
color: #8898aa;
border: 1px solid #cad1d7;
border-radius: .375rem;
background: #fff url('data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 4 5\'%3E%3Cpath fill=\'%2332325d\' d=\'M2 0L0 2h4zm0 5L0 3h4z\'/%3E%3C/svg%3E') no-repeat right .75rem center;
background-size: 8px 10px;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, .075);
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.custom-select:focus
{
border-color: rgba(50, 151, 211, .25);
outline: 0;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, .075), 0 0 0 0 rgba(50, 151, 211, .5);
}
.custom-select:focus::-ms-value
{
color: #8898aa;
background-color: #fff;
}
.custom-select[multiple],
.custom-select[size]:not([size='1'])
{
height: auto;
padding-right: .75rem;
background-image: none;
}
.custom-select:disabled
{
color: #8898aa;
background-color: #e9ecef;
}
.custom-select::-ms-expand
{
opacity: 0;
}
.custom-select-sm
{
font-size: 75%;
height: calc(1.8125rem + 2px);
padding-top: .375rem;
padding-bottom: .375rem;
}
.custom-select-lg
{
font-size: 125%;
height: calc(3.625rem + 2px);
padding-top: .375rem;
padding-bottom: .375rem;
}
.custom-file
{
position: relative;
display: inline-block;
width: 100%;
height: calc(2.75rem + 2px);
margin-bottom: 0;
}
.custom-file-input
{
position: relative;
z-index: 2;
width: 100%;
height: calc(2.75rem + 2px);
margin: 0;
opacity: 0;
}
.custom-file-input:focus ~ .custom-file-label
{
border-color: rgba(50, 151, 211, .25);
box-shadow: none;
}
.custom-file-input:focus ~ .custom-file-label::after
{
border-color: rgba(50, 151, 211, .25);
}
.custom-file-input:disabled ~ .custom-file-label
{
background-color: #e9ecef;
}
.custom-file-input:lang(en) ~ .custom-file-label::after
{
content: 'Browse';
}
.custom-file-label
{
line-height: 1.5;
position: absolute;
z-index: 1;
top: 0;
right: 0;
left: 0;
height: calc(2.75rem + 2px);
padding: .625rem .75rem;
color: #8898aa;
border: 1px solid #cad1d7;
border-radius: .375rem;
background-color: #fff;
box-shadow: none;
}
.custom-file-label::after
{
line-height: 1.5;
position: absolute;
z-index: 3;
top: 0;
right: 0;
bottom: 0;
display: block;
height: 2.75rem;
padding: .625rem .75rem;
content: 'Browse';
color: #8898aa;
border-left: 1px solid #cad1d7;
border-radius: 0 .375rem .375rem 0;
background-color: #fff;
}
.custom-range
{
width: 100%;
padding-left: 0;
background-color: transparent;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.custom-range:focus
{
outline: none;
}
.custom-range:focus::-webkit-slider-thumb
{
box-shadow: 0 0 0 1px #f8f9fe, none;
}
.custom-range:focus::-moz-range-thumb
{
box-shadow: 0 0 0 1px #f8f9fe, none;
}
.custom-range:focus::-ms-thumb
{
box-shadow: 0 0 0 1px #f8f9fe, none;
}
.custom-range::-moz-focus-outer
{
border: 0;
}
.custom-range::-webkit-slider-thumb
{
width: 1rem;
height: 1rem;
margin-top: -.25rem;
transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
border: 0;
border-radius: 1rem;
background-color: #5e72e4;
box-shadow: 0 .1rem .25rem rgba(0, 0, 0, .1);
-webkit-appearance: none;
appearance: none;
}
@media screen and (prefers-reduced-motion: reduce)
{
.custom-range::-webkit-slider-thumb
{
transition: none;
}
}
.custom-range::-webkit-slider-thumb:active
{
background-color: #f7f8fe;
}
.custom-range::-webkit-slider-runnable-track
{
width: 100%;
height: .5rem;
cursor: pointer;
color: transparent;
border-color: transparent;
border-radius: 1rem;
background-color: #dee2e6;
box-shadow: inset 0 .25rem .25rem rgba(0, 0, 0, .1);
}
.custom-range::-moz-range-thumb
{
width: 1rem;
height: 1rem;
transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
border: 0;
border-radius: 1rem;
background-color: #5e72e4;
box-shadow: 0 .1rem .25rem rgba(0, 0, 0, .1);
-moz-appearance: none;
appearance: none;
}
@media screen and (prefers-reduced-motion: reduce)
{
.custom-range::-moz-range-thumb
{
transition: none;
}
}
.custom-range::-moz-range-thumb:active
{
background-color: #f7f8fe;
}
.custom-range::-moz-range-track
{
width: 100%;
height: .5rem;
cursor: pointer;
color: transparent;
border-color: transparent;
border-radius: 1rem;
background-color: #dee2e6;
box-shadow: inset 0 .25rem .25rem rgba(0, 0, 0, .1);
}
.custom-range::-ms-thumb
{
width: 1rem;
height: 1rem;
margin-top: 0;
margin-right: 0;
margin-left: 0;
transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
border: 0;
border-radius: 1rem;
background-color: #5e72e4;
box-shadow: 0 .1rem .25rem rgba(0, 0, 0, .1);
appearance: none;
}
@media screen and (prefers-reduced-motion: reduce)
{
.custom-range::-ms-thumb
{
transition: none;
}
}
.custom-range::-ms-thumb:active
{
background-color: #f7f8fe;
}
.custom-range::-ms-track
{
width: 100%;
height: .5rem;
cursor: pointer;
color: transparent;
border-width: .5rem;
border-color: transparent;
background-color: transparent;
box-shadow: inset 0 .25rem .25rem rgba(0, 0, 0, .1);
}
.custom-range::-ms-fill-lower
{
border-radius: 1rem;
background-color: #dee2e6;
}
.custom-range::-ms-fill-upper
{
margin-right: 15px;
border-radius: 1rem;
background-color: #dee2e6;
}
.custom-control-label::before,
.custom-file-label,
.custom-select
{
transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}
@media screen and (prefers-reduced-motion: reduce)
{
.custom-control-label::before,
.custom-file-label,
.custom-select
{
transition: none;
}
}
.nav
{
display: flex;
margin-bottom: 0;
padding-left: 0;
list-style: none;
flex-wrap: wrap;
}
.nav-link
{
display: block;
padding: .25rem .75rem;
}
.nav-link:hover,
.nav-link:focus
{
text-decoration: none;
}
.nav-link.disabled
{
color: #8898aa;
}
.nav-tabs
{
border-bottom: 1px solid #dee2e6;
}
.nav-tabs .nav-item
{
margin-bottom: -1px;
}
.nav-tabs .nav-link
{
border: 1px solid transparent;
border-top-left-radius: .375rem;
border-top-right-radius: .375rem;
}
.nav-tabs .nav-link:hover,
.nav-tabs .nav-link:focus
{
border-color: #e9ecef #e9ecef #dee2e6;
}
.nav-tabs .nav-link.disabled
{
color: #8898aa;
border-color: transparent;
background-color: transparent;
}
.nav-tabs .nav-link.active,
.nav-tabs .nav-item.show .nav-link
{
color: #525f7f;
border-color: #dee2e6 #dee2e6 #f8f9fe;
background-color: #f8f9fe;
}
.nav-tabs .dropdown-menu
{
margin-top: -1px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.nav-pills .nav-link
{
border-radius: .375rem;
}
.nav-pills .nav-link.active,
.nav-pills .show > .nav-link
{
color: #fff;
background-color: #5e72e4;
}
.nav-fill .nav-item
{
text-align: center;
flex: 1 1 auto;
}
.nav-justified .nav-item
{
text-align: center;
flex-basis: 0;
flex-grow: 1;
}
.tab-content > .tab-pane
{
display: none;
}
.tab-content > .active
{
display: block;
}
.navbar
{
position: relative;
display: flex;
padding: 1rem 1rem;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
}
.navbar > .container,
.navbar > .container-fluid
{
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
}
.navbar-brand
{
font-size: 1.25rem;
line-height: inherit;
display: inline-block;
margin-right: 1rem;
padding-top: .0625rem;
padding-bottom: .0625rem;
white-space: nowrap;
}
.navbar-brand:hover,
.navbar-brand:focus
{
text-decoration: none;
}
.navbar-nav
{
display: flex;
flex-direction: column;
margin-bottom: 0;
padding-left: 0;
list-style: none;
}
.navbar-nav .nav-link
{
padding-right: 0;
padding-left: 0;
}
.navbar-nav .dropdown-menu
{
position: static;
float: none;
}
.navbar-text
{
display: inline-block;
padding-top: .25rem;
padding-bottom: .25rem;
}
.navbar-collapse
{
flex-basis: 100%;
flex-grow: 1;
align-items: center;
}
.navbar-toggler
{
font-size: 1.25rem;
line-height: 1;
padding: .25rem .75rem;
border: 1px solid transparent;
border-radius: .375rem;
background-color: transparent;
}
.navbar-toggler:hover,
.navbar-toggler:focus
{
text-decoration: none;
}
.navbar-toggler:not(:disabled):not(.disabled)
{
cursor: pointer;
}
.navbar-toggler-icon
{
display: inline-block;
width: 1.5em;
height: 1.5em;
content: '';
vertical-align: middle;
background: no-repeat center center;
background-size: 100% 100%;
}
@media (max-width: 575.98px)
{
.navbar-expand-sm > .container,
.navbar-expand-sm > .container-fluid
{
padding-right: 0;
padding-left: 0;
}
}
@media (min-width: 576px)
{
.navbar-expand-sm
{
flex-flow: row nowrap;
justify-content: flex-start;
}
.navbar-expand-sm .navbar-nav
{
flex-direction: row;
}
.navbar-expand-sm .navbar-nav .dropdown-menu
{
position: absolute;
}
.navbar-expand-sm .navbar-nav .nav-link
{
padding-right: 1rem;
padding-left: 1rem;
}
.navbar-expand-sm > .container,
.navbar-expand-sm > .container-fluid
{
flex-wrap: nowrap;
}
.navbar-expand-sm .navbar-collapse
{
display: flex !important;
flex-basis: auto;
}
.navbar-expand-sm .navbar-toggler
{
display: none;
}
}
@media (max-width: 767.98px)
{
.navbar-expand-md > .container,
.navbar-expand-md > .container-fluid
{
padding-right: 0;
padding-left: 0;
}
}
@media (min-width: 768px)
{
.navbar-expand-md
{
flex-flow: row nowrap;
justify-content: flex-start;
}
.navbar-expand-md .navbar-nav
{
flex-direction: row;
}
.navbar-expand-md .navbar-nav .dropdown-menu
{
position: absolute;
}
.navbar-expand-md .navbar-nav .nav-link
{
padding-right: 1rem;
padding-left: 1rem;
}
.navbar-expand-md > .container,
.navbar-expand-md > .container-fluid
{
flex-wrap: nowrap;
}
.navbar-expand-md .navbar-collapse
{
display: flex !important;
flex-basis: auto;
}
.navbar-expand-md .navbar-toggler
{
display: none;
}
}
@media (max-width: 991.98px)
{
.navbar-expand-lg > .container,
.navbar-expand-lg > .container-fluid
{
padding-right: 0;
padding-left: 0;
}
}
@media (min-width: 992px)
{
.navbar-expand-lg
{
flex-flow: row nowrap;
justify-content: flex-start;
}
.navbar-expand-lg .navbar-nav
{
flex-direction: row;
}
.navbar-expand-lg .navbar-nav .dropdown-menu
{
position: absolute;
}
.navbar-expand-lg .navbar-nav .nav-link
{
padding-right: 1rem;
padding-left: 1rem;
}
.navbar-expand-lg > .container,
.navbar-expand-lg > .container-fluid
{
flex-wrap: nowrap;
}
.navbar-expand-lg .navbar-collapse
{
display: flex !important;
flex-basis: auto;
}
.navbar-expand-lg .navbar-toggler
{
display: none;
}
}
@media (max-width: 1199.98px)
{
.navbar-expand-xl > .container,
.navbar-expand-xl > .container-fluid
{
padding-right: 0;
padding-left: 0;
}
}
@media (min-width: 1200px)
{
.navbar-expand-xl
{
flex-flow: row nowrap;
justify-content: flex-start;
}
.navbar-expand-xl .navbar-nav
{
flex-direction: row;
}
.navbar-expand-xl .navbar-nav .dropdown-menu
{
position: absolute;
}
.navbar-expand-xl .navbar-nav .nav-link
{
padding-right: 1rem;
padding-left: 1rem;
}
.navbar-expand-xl > .container,
.navbar-expand-xl > .container-fluid
{
flex-wrap: nowrap;
}
.navbar-expand-xl .navbar-collapse
{
display: flex !important;
flex-basis: auto;
}
.navbar-expand-xl .navbar-toggler
{
display: none;
}
}
.navbar-expand
{
flex-flow: row nowrap;
justify-content: flex-start;
}
.navbar-expand > .container,
.navbar-expand > .container-fluid
{
padding-right: 0;
padding-left: 0;
}
.navbar-expand .navbar-nav
{
flex-direction: row;
}
.navbar-expand .navbar-nav .dropdown-menu
{
position: absolute;
}
.navbar-expand .navbar-nav .nav-link
{
padding-right: 1rem;
padding-left: 1rem;
}
.navbar-expand > .container,
.navbar-expand > .container-fluid
{
flex-wrap: nowrap;
}
.navbar-expand .navbar-collapse
{
display: flex !important;
flex-basis: auto;
}
.navbar-expand .navbar-toggler
{
display: none;
}
.navbar-light .navbar-brand
{
color: rgba(0, 0, 0, .9);
}
.navbar-light .navbar-brand:hover,
.navbar-light .navbar-brand:focus
{
color: rgba(0, 0, 0, .9);
}
.navbar-light .navbar-nav .nav-link
{
color: rgba(0, 0, 0, .5);
}
.navbar-light .navbar-nav .nav-link:hover,
.navbar-light .navbar-nav .nav-link:focus
{
color: rgba(0, 0, 0, .7);
}
.navbar-light .navbar-nav .nav-link.disabled
{
color: rgba(0, 0, 0, .3);
}
.navbar-light .navbar-nav .show > .nav-link,
.navbar-light .navbar-nav .active > .nav-link,
.navbar-light .navbar-nav .nav-link.show,
.navbar-light .navbar-nav .nav-link.active
{
color: rgba(0, 0, 0, .9);
}
.navbar-light .navbar-toggler
{
color: rgba(0, 0, 0, .5);
border-color: transparent;
}
.navbar-light .navbar-toggler-icon
{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg viewBox=\'0 0 30 30\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cpath stroke=\'rgba(0, 0, 0, 0.5)\' stroke-width=\'2\' stroke-linecap=\'round\' stroke-miterlimit=\'10\' d=\'M4 7h22M4 15h22M4 23h22\'/%3E%3C/svg%3E');
}
.navbar-light .navbar-text
{
color: rgba(0, 0, 0, .5);
}
.navbar-light .navbar-text a
{
color: rgba(0, 0, 0, .9);
}
.navbar-light .navbar-text a:hover,
.navbar-light .navbar-text a:focus
{
color: rgba(0, 0, 0, .9);
}
.navbar-dark .navbar-brand
{
color: rgba(255, 255, 255, .65);
}
.navbar-dark .navbar-brand:hover,
.navbar-dark .navbar-brand:focus
{
color: rgba(255, 255, 255, .65);
}
.navbar-dark .navbar-nav .nav-link
{
color: rgba(255, 255, 255, .95);
}
.navbar-dark .navbar-nav .nav-link:hover,
.navbar-dark .navbar-nav .nav-link:focus
{
color: rgba(255, 255, 255, .65);
}
.navbar-dark .navbar-nav .nav-link.disabled
{
color: rgba(255, 255, 255, .25);
}
.navbar-dark .navbar-nav .show > .nav-link,
.navbar-dark .navbar-nav .active > .nav-link,
.navbar-dark .navbar-nav .nav-link.show,
.navbar-dark .navbar-nav .nav-link.active
{
color: rgba(255, 255, 255, .65);
}
.navbar-dark .navbar-toggler
{
color: rgba(255, 255, 255, .95);
border-color: transparent;
}
.navbar-dark .navbar-toggler-icon
{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg viewBox=\'0 0 30 30\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cpath stroke=\'rgba(255, 255, 255, 0.95)\' stroke-width=\'2\' stroke-linecap=\'round\' stroke-miterlimit=\'10\' d=\'M4 7h22M4 15h22M4 23h22\'/%3E%3C/svg%3E');
}
.navbar-dark .navbar-text
{
color: rgba(255, 255, 255, .95);
}
.navbar-dark .navbar-text a
{
color: rgba(255, 255, 255, .65);
}
.navbar-dark .navbar-text a:hover,
.navbar-dark .navbar-text a:focus
{
color: rgba(255, 255, 255, .65);
}
.card
{
position: relative;
display: flex;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
border: 1px solid rgba(0, 0, 0, .05);
border-radius: .375rem;
background-color: #fff;
background-clip: border-box;
}
.card > hr
{
margin-right: 0;
margin-left: 0;
}
.card > .list-group:first-child .list-group-item:first-child
{
border-top-left-radius: .375rem;
border-top-right-radius: .375rem;
}
.card > .list-group:last-child .list-group-item:last-child
{
border-bottom-right-radius: .375rem;
border-bottom-left-radius: .375rem;
}
.card-body
{
padding: 1.5rem;
flex: 1 1 auto;
}
.card-title
{
margin-bottom: 1.25rem;
}
.card-subtitle
{
margin-top: -.625rem;
margin-bottom: 0;
}
.card-text:last-child
{
margin-bottom: 0;
}
.card-link:hover
{
text-decoration: none;
}
.card-link + .card-link
{
margin-left: 1.5rem;
}
.card-header
{
margin-bottom: 0;
padding: 1.25rem 1.5rem;
border-bottom: 1px solid rgba(0, 0, 0, .05);
background-color: #fff;
}
.card-header:first-child
{
border-radius: calc(.375rem - 1px) calc(.375rem - 1px) 0 0;
}
.card-header + .list-group .list-group-item:first-child
{
border-top: 0;
}
.card-footer
{
padding: 1.25rem 1.5rem;
border-top: 1px solid rgba(0, 0, 0, .05);
background-color: #fff;
}
.card-footer:last-child
{
border-radius: 0 0 calc(.375rem - 1px) calc(.375rem - 1px);
}
.card-header-tabs
{
margin-right: -.75rem;
margin-bottom: -1.25rem;
margin-left: -.75rem;
border-bottom: 0;
}
.card-header-pills
{
margin-right: -.75rem;
margin-left: -.75rem;
}
.card-img-overlay
{
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 1.25rem;
}
.card-img
{
width: 100%;
border-radius: calc(.375rem - 1px);
}
.card-img-top
{
width: 100%;
border-top-left-radius: calc(.375rem - 1px);
border-top-right-radius: calc(.375rem - 1px);
}
.card-img-bottom
{
width: 100%;
border-bottom-right-radius: calc(.375rem - 1px);
border-bottom-left-radius: calc(.375rem - 1px);
}
.card-deck
{
display: flex;
flex-direction: column;
}
.card-deck .card
{
margin-bottom: 15px;
}
@media (min-width: 576px)
{
.card-deck
{
margin-right: -15px;
margin-left: -15px;
flex-flow: row wrap;
}
.card-deck .card
{
display: flex;
flex-direction: column;
margin-right: 15px;
margin-bottom: 0;
margin-left: 15px;
flex: 1 0;
}
}
.card-group
{
display: flex;
flex-direction: column;
}
.card-group > .card
{
margin-bottom: 15px;
}
@media (min-width: 576px)
{
.card-group
{
flex-flow: row wrap;
}
.card-group > .card
{
margin-bottom: 0;
flex: 1 0;
}
.card-group > .card + .card
{
margin-left: 0;
border-left: 0;
}
.card-group > .card:first-child
{
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.card-group > .card:first-child .card-img-top,
.card-group > .card:first-child .card-header
{
border-top-right-radius: 0;
}
.card-group > .card:first-child .card-img-bottom,
.card-group > .card:first-child .card-footer
{
border-bottom-right-radius: 0;
}
.card-group > .card:last-child
{
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.card-group > .card:last-child .card-img-top,
.card-group > .card:last-child .card-header
{
border-top-left-radius: 0;
}
.card-group > .card:last-child .card-img-bottom,
.card-group > .card:last-child .card-footer
{
border-bottom-left-radius: 0;
}
.card-group > .card:only-child
{
border-radius: .375rem;
}
.card-group > .card:only-child .card-img-top,
.card-group > .card:only-child .card-header
{
border-top-left-radius: .375rem;
border-top-right-radius: .375rem;
}
.card-group > .card:only-child .card-img-bottom,
.card-group > .card:only-child .card-footer
{
border-bottom-right-radius: .375rem;
border-bottom-left-radius: .375rem;
}
.card-group > .card:not(:first-child):not(:last-child):not(:only-child)
{
border-radius: 0;
}
.card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-img-top,
.card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,
.card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-header,
.card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-footer
{
border-radius: 0;
}
}
.card-columns .card
{
margin-bottom: 1.25rem;
}
@media (min-width: 576px)
{
.card-columns
{
column-count: 3;
column-gap: 1.25rem;
orphans: 1;
widows: 1;
}
.card-columns .card
{
display: inline-block;
width: 100%;
}
}
.accordion .card:not(:first-of-type):not(:last-of-type)
{
border-bottom: 0;
border-radius: 0;
}
.accordion .card:not(:first-of-type) .card-header:first-child
{
border-radius: 0;
}
.accordion .card:first-of-type
{
border-bottom: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.accordion .card:last-of-type
{
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.breadcrumb
{
display: flex;
margin-bottom: 1rem;
padding: .75rem 1rem;
list-style: none;
border-radius: .375rem;
background-color: #e9ecef;
flex-wrap: wrap;
}
.breadcrumb-item + .breadcrumb-item
{
padding-left: .5rem;
}
.breadcrumb-item + .breadcrumb-item::before
{
display: inline-block;
padding-right: .5rem;
content: '/';
color: #8898aa;
}
.breadcrumb-item + .breadcrumb-item:hover::before
{
text-decoration: underline;
}
.breadcrumb-item + .breadcrumb-item:hover::before
{
text-decoration: none;
}
.breadcrumb-item.active
{
color: #8898aa;
}
.pagination
{
display: flex;
padding-left: 0;
list-style: none;
border-radius: .375rem;
}
.page-link
{
line-height: 1.25;
position: relative;
display: block;
margin-left: -1px;
padding: .5rem .75rem;
color: #8898aa;
border: 1px solid #dee2e6;
background-color: #fff;
}
.page-link:hover
{
z-index: 2;
text-decoration: none;
color: #8898aa;
border-color: #dee2e6;
background-color: #dee2e6;
}
.page-link:focus
{
z-index: 2;
outline: 0;
box-shadow: none;
}
.page-link:not(:disabled):not(.disabled)
{
cursor: pointer;
}
.page-item:first-child .page-link
{
margin-left: 0;
border-top-left-radius: .375rem;
border-bottom-left-radius: .375rem;
}
.page-item:last-child .page-link
{
border-top-right-radius: .375rem;
border-bottom-right-radius: .375rem;
}
.page-item.active .page-link
{
z-index: 1;
color: #fff;
border-color: #5e72e4;
background-color: #5e72e4;
}
.page-item.disabled .page-link
{
cursor: auto;
pointer-events: none;
color: #8898aa;
border-color: #dee2e6;
background-color: #fff;
}
.pagination-lg .page-link
{
font-size: 1.25rem;
line-height: 1.5;
padding: .75rem 1.5rem;
}
.pagination-lg .page-item:first-child .page-link
{
border-top-left-radius: .4375rem;
border-bottom-left-radius: .4375rem;
}
.pagination-lg .page-item:last-child .page-link
{
border-top-right-radius: .4375rem;
border-bottom-right-radius: .4375rem;
}
.pagination-sm .page-link
{
font-size: .875rem;
line-height: 1.5;
padding: .25rem .5rem;
}
.pagination-sm .page-item:first-child .page-link
{
border-top-left-radius: .25rem;
border-bottom-left-radius: .25rem;
}
.pagination-sm .page-item:last-child .page-link
{
border-top-right-radius: .25rem;
border-bottom-right-radius: .25rem;
}
.badge
{
font-size: 66%;
font-weight: 600;
line-height: 1;
display: inline-block;
padding: .35rem .375rem;
text-align: center;
vertical-align: baseline;
white-space: nowrap;
border-radius: .375rem;
}
.badge:empty
{
display: none;
}
.btn .badge
{
position: relative;
top: -1px;
}
.badge-pill
{
padding-right: .875em;
padding-left: .875em;
border-radius: 10rem;
}
.badge-primary
{
color: #2643e9;
background-color: rgba(203, 210, 246, .5);
}
.badge-primary[href]:hover,
.badge-primary[href]:focus
{
text-decoration: none;
color: #fff;
background-color: #324cdd;
}
.badge-secondary
{
color: #cfe3f1;
background-color: rgba(255, 255, 255, .5);
}
.badge-secondary[href]:hover,
.badge-secondary[href]:focus
{
text-decoration: none;
color: #212529;
background-color: #d2e3ee;
}
.badge-success
{
color: #1aae6f;
background-color: rgba(147, 231, 195, .5);
}
.badge-success[href]:hover,
.badge-success[href]:focus
{
text-decoration: none;
color: #fff;
background-color: #24a46d;
}
.badge-info
{
color: #03acca;
background-color: rgba(136, 230, 247, .5);
}
.badge-info[href]:hover,
.badge-info[href]:focus
{
text-decoration: none;
color: #fff;
background-color: #0da5c0;
}
.badge-warning
{
color: #ff3709;
background-color: rgba(254, 201, 189, .5);
}
.badge-warning[href]:hover,
.badge-warning[href]:focus
{
text-decoration: none;
color: #fff;
background-color: #fa3a0e;
}
.badge-danger
{
color: #f80031;
background-color: rgba(251, 175, 190, .5);
}
.badge-danger[href]:hover,
.badge-danger[href]:focus
{
text-decoration: none;
color: #fff;
background-color: #ec0c38;
}
.badge-light
{
color: #879cb0;
background-color: rgba(244, 245, 246, .5);
}
.badge-light[href]:hover,
.badge-light[href]:focus
{
text-decoration: none;
color: #fff;
background-color: #919ca6;
}
.badge-dark
{
color: #090c0e;
background-color: rgba(90, 101, 112, .5);
}
.badge-dark[href]:hover,
.badge-dark[href]:focus
{
text-decoration: none;
color: #fff;
background-color: #0a0c0d;
}
.badge-default
{
color: #091428;
background-color: rgba(52, 98, 175, .5);
}
.badge-default[href]:hover,
.badge-default[href]:focus
{
text-decoration: none;
color: #fff;
background-color: #0b1526;
}
.badge-white
{
color: #e8e3e3;
background-color: rgba(255, 255, 255, .5);
}
.badge-white[href]:hover,
.badge-white[href]:focus
{
text-decoration: none;
color: #212529;
background-color: #e6e6e6;
}
.badge-neutral
{
color: #e8e3e3;
background-color: rgba(255, 255, 255, .5);
}
.badge-neutral[href]:hover,
.badge-neutral[href]:focus
{
text-decoration: none;
color: #212529;
background-color: #e6e6e6;
}
.badge-darker
{
color: black;
background-color: rgba(64, 64, 64, .5);
}
.badge-darker[href]:hover,
.badge-darker[href]:focus
{
text-decoration: none;
color: #fff;
background-color: black;
}
.jumbotron
{
margin-bottom: 2rem;
padding: 2rem 1rem;
border-radius: .4375rem;
background-color: #e9ecef;
}
@media (min-width: 576px)
{
.jumbotron
{
padding: 4rem 2rem;
}
}
.jumbotron-fluid
{
padding-right: 0;
padding-left: 0;
border-radius: 0;
}
.alert
{
position: relative;
margin-bottom: 1rem;
padding: 1rem 1.5rem;
border: 1px solid transparent;
border-radius: .375rem;
}
.alert-heading
{
color: inherit;
}
.alert-link
{
font-weight: 600;
}
.alert-dismissible
{
padding-right: 4.5rem;
}
.alert-dismissible .close
{
position: absolute;
top: 0;
right: 0;
padding: 1rem 1.5rem;
color: inherit;
}
.alert-primary
{
color: #fff;
border-color: #7889e8;
background-color: #7889e8;
}
.alert-primary hr
{
border-top-color: #6276e4;
}
.alert-primary .alert-link
{
color: #324cdd;
}
.alert-secondary
{
color: #212529;
border-color: #f8fbfc;
background-color: #f8fbfc;
}
.alert-secondary hr
{
border-top-color: #e6f1f4;
}
.alert-secondary .alert-link
{
color: #d2e3ee;
}
.alert-success
{
color: #fff;
border-color: #4fd69c;
background-color: #4fd69c;
}
.alert-success hr
{
border-top-color: #3ad190;
}
.alert-success .alert-link
{
color: #24a46d;
}
.alert-info
{
color: #fff;
border-color: #37d5f2;
background-color: #37d5f2;
}
.alert-info hr
{
border-top-color: #1fd0f0;
}
.alert-info .alert-link
{
color: #0da5c0;
}
.alert-warning
{
color: #fff;
border-color: #fc7c5f;
background-color: #fc7c5f;
}
.alert-warning hr
{
border-top-color: #fc6846;
}
.alert-warning .alert-link
{
color: #fa3a0e;
}
.alert-danger
{
color: #fff;
border-color: #f75676;
background-color: #f75676;
}
.alert-danger hr
{
border-top-color: #f63e62;
}
.alert-danger .alert-link
{
color: #ec0c38;
}
.alert-light
{
color: #fff;
border-color: #bac1c8;
background-color: #bac1c8;
}
.alert-light hr
{
border-top-color: #acb4bd;
}
.alert-light .alert-link
{
color: #919ca6;
}
.alert-dark
{
color: #fff;
border-color: #45484b;
background-color: #45484b;
}
.alert-dark hr
{
border-top-color: #393b3e;
}
.alert-dark .alert-link
{
color: #0a0c0d;
}
.alert-default
{
color: #fff;
border-color: #3c4d69;
background-color: #3c4d69;
}
.alert-default hr
{
border-top-color: #334159;
}
.alert-default .alert-link
{
color: #0b1526;
}
.alert-white
{
color: #212529;
border-color: white;
background-color: white;
}
.alert-white hr
{
border-top-color: #f2f2f2;
}
.alert-white .alert-link
{
color: #e6e6e6;
}
.alert-neutral
{
color: #212529;
border-color: white;
background-color: white;
}
.alert-neutral hr
{
border-top-color: #f2f2f2;
}
.alert-neutral .alert-link
{
color: #e6e6e6;
}
.alert-darker
{
color: #fff;
border-color: #292929;
background-color: #292929;
}
.alert-darker hr
{
border-top-color: #1c1c1c;
}
.alert-darker .alert-link
{
color: black;
}
@keyframes progress-bar-stripes
{
from
{
background-position: 1rem 0;
}
to
{
background-position: 0 0;
}
}
.progress
{
font-size: .75rem;
display: flex;
overflow: hidden;
height: 1rem;
border-radius: .375rem;
background-color: #e9ecef;
box-shadow: inset 0 .1rem .1rem rgba(0, 0, 0, .1);
}
.progress-bar
{
display: flex;
flex-direction: column;
transition: width .6s ease;
text-align: center;
white-space: nowrap;
color: #fff;
background-color: #5e72e4;
justify-content: center;
}
@media screen and (prefers-reduced-motion: reduce)
{
.progress-bar
{
transition: none;
}
}
.progress-bar-striped
{
background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-size: 1rem 1rem;
}
.progress-bar-animated
{
animation: progress-bar-stripes 1s linear infinite;
}
.media
{
display: flex;
align-items: flex-start;
}
.media-body
{
flex: 1 1;
}
.list-group
{
display: flex;
flex-direction: column;
margin-bottom: 0;
padding-left: 0;
}
.list-group-item-action
{
width: 100%;
text-align: inherit;
color: #525f7f;
}
.list-group-item-action:hover,
.list-group-item-action:focus
{
text-decoration: none;
color: #525f7f;
background-color: #f6f9fc;
}
.list-group-item-action:active
{
color: #525f7f;
background-color: #e9ecef;
}
.list-group-item
{
position: relative;
display: block;
margin-bottom: -1px;
padding: 1rem 1rem;
border: 1px solid #e9ecef;
background-color: #fff;
}
.list-group-item:first-child
{
border-top-left-radius: .375rem;
border-top-right-radius: .375rem;
}
.list-group-item:last-child
{
margin-bottom: 0;
border-bottom-right-radius: .375rem;
border-bottom-left-radius: .375rem;
}
.list-group-item:hover,
.list-group-item:focus
{
z-index: 1;
text-decoration: none;
}
.list-group-item.disabled,
.list-group-item:disabled
{
color: #8898aa;
background-color: #fff;
}
.list-group-item.active
{
z-index: 2;
color: #fff;
border-color: #5e72e4;
background-color: #5e72e4;
}
.list-group-flush .list-group-item
{
border-right: 0;
border-left: 0;
border-radius: 0;
}
.list-group-flush:first-child .list-group-item:first-child
{
border-top: 0;
}
.list-group-flush:last-child .list-group-item:last-child
{
border-bottom: 0;
}
.list-group-item-primary
{
color: #313b77;
background-color: #d2d8f7;
}
.list-group-item-primary.list-group-item-action:hover,
.list-group-item-primary.list-group-item-action:focus
{
color: #313b77;
background-color: #bcc5f3;
}
.list-group-item-primary.list-group-item-action.active
{
color: #fff;
border-color: #313b77;
background-color: #313b77;
}
.list-group-item-secondary
{
color: #808283;
background-color: #fdfefe;
}
.list-group-item-secondary.list-group-item-action:hover,
.list-group-item-secondary.list-group-item-action:focus
{
color: #808283;
background-color: #ecf6f6;
}
.list-group-item-secondary.list-group-item-action.active
{
color: #fff;
border-color: #808283;
background-color: #808283;
}
.list-group-item-success
{
color: #176b47;
background-color: #c4f1de;
}
.list-group-item-success.list-group-item-action:hover,
.list-group-item-success.list-group-item-action:focus
{
color: #176b47;
background-color: #afecd2;
}
.list-group-item-success.list-group-item-action.active
{
color: #fff;
border-color: #176b47;
background-color: #176b47;
}
.list-group-item-info
{
color: #096b7c;
background-color: #bcf1fb;
}
.list-group-item-info.list-group-item-action:hover,
.list-group-item-info.list-group-item-action:focus
{
color: #096b7c;
background-color: #a4ecfa;
}
.list-group-item-info.list-group-item-action.active
{
color: #fff;
border-color: #096b7c;
background-color: #096b7c;
}
.list-group-item-warning
{
color: #833321;
background-color: #fed3ca;
}
.list-group-item-warning.list-group-item-action:hover,
.list-group-item-warning.list-group-item-action:focus
{
color: #833321;
background-color: #febeb1;
}
.list-group-item-warning.list-group-item-action.active
{
color: #fff;
border-color: #833321;
background-color: #833321;
}
.list-group-item-danger
{
color: #7f1c30;
background-color: #fcc7d1;
}
.list-group-item-danger.list-group-item-action:hover,
.list-group-item-danger.list-group-item-action:focus
{
color: #7f1c30;
background-color: #fbafbd;
}
.list-group-item-danger.list-group-item-action.active
{
color: #fff;
border-color: #7f1c30;
background-color: #7f1c30;
}
.list-group-item-light
{
color: #5a5e62;
background-color: #e8eaed;
}
.list-group-item-light.list-group-item-action:hover,
.list-group-item-light.list-group-item-action:focus
{
color: #5a5e62;
background-color: #dadde2;
}
.list-group-item-light.list-group-item-action.active
{
color: #fff;
border-color: #5a5e62;
background-color: #5a5e62;
}
.list-group-item-dark
{
color: #111315;
background-color: #c1c2c3;
}
.list-group-item-dark.list-group-item-action:hover,
.list-group-item-dark.list-group-item-action:focus
{
color: #111315;
background-color: #b4b5b6;
}
.list-group-item-dark.list-group-item-action.active
{
color: #fff;
border-color: #111315;
background-color: #111315;
}
.list-group-item-default
{
color: #0c1628;
background-color: #bec4cd;
}
.list-group-item-default.list-group-item-action:hover,
.list-group-item-default.list-group-item-action:focus
{
color: #0c1628;
background-color: #b0b7c2;
}
.list-group-item-default.list-group-item-action.active
{
color: #fff;
border-color: #0c1628;
background-color: #0c1628;
}
.list-group-item-white
{
color: #858585;
background-color: white;
}
.list-group-item-white.list-group-item-action:hover,
.list-group-item-white.list-group-item-action:focus
{
color: #858585;
background-color: #f2f2f2;
}
.list-group-item-white.list-group-item-action.active
{
color: #fff;
border-color: #858585;
background-color: #858585;
}
.list-group-item-neutral
{
color: #858585;
background-color: white;
}
.list-group-item-neutral.list-group-item-action:hover,
.list-group-item-neutral.list-group-item-action:focus
{
color: #858585;
background-color: #f2f2f2;
}
.list-group-item-neutral.list-group-item-action.active
{
color: #fff;
border-color: #858585;
background-color: #858585;
}
.list-group-item-darker
{
color: black;
background-color: #b8b8b8;
}
.list-group-item-darker.list-group-item-action:hover,
.list-group-item-darker.list-group-item-action:focus
{
color: black;
background-color: #ababab;
}
.list-group-item-darker.list-group-item-action.active
{
color: #fff;
border-color: black;
background-color: black;
}
.close
{
font-size: 1.5rem;
font-weight: 600;
line-height: 1;
float: right;
opacity: .5;
color: rgba(0, 0, 0, .6);
text-shadow: none;
}
.close:not(:disabled):not(.disabled)
{
cursor: pointer;
}
.close:not(:disabled):not(.disabled):hover,
.close:not(:disabled):not(.disabled):focus
{
text-decoration: none;
opacity: .75;
color: rgba(0, 0, 0, .6);
}
button.close
{
padding: 0;
border: 0;
background-color: transparent;
-webkit-appearance: none;
}
.modal-open
{
overflow: hidden;
}
.modal-open .modal
{
overflow-x: hidden;
overflow-y: auto;
}
.modal
{
position: fixed;
z-index: 1050;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
overflow: hidden;
outline: 0;
}
.modal-dialog
{
position: relative;
width: auto;
margin: .5rem;
pointer-events: none;
}
.modal.fade .modal-dialog
{
transition: transform .3s ease-out;
transform: translate(0, -25%);
}
@media screen and (prefers-reduced-motion: reduce)
{
.modal.fade .modal-dialog
{
transition: none;
}
}
.modal.show .modal-dialog
{
transform: translate(0, 0);
}
.modal-dialog-centered
{
display: flex;
min-height: calc(100% - (.5rem * 2));
align-items: center;
}
.modal-dialog-centered::before
{
display: block;
height: calc(100vh - (.5rem * 2));
content: '';
}
.modal-content
{
position: relative;
display: flex;
flex-direction: column;
width: 100%;
pointer-events: auto;
border: 0 solid rgba(0, 0, 0, .2);
border-radius: .4375rem;
outline: 0;
background-color: #fff;
background-clip: padding-box;
box-shadow: 0 15px 35px rgba(50, 50, 93, .2), 0 5px 15px rgba(0, 0, 0, .17);
}
.modal-backdrop
{
position: fixed;
z-index: 1040;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #000;
}
.modal-backdrop.fade
{
opacity: 0;
}
.modal-backdrop.show
{
opacity: .16;
}
.modal-header
{
display: flex;
padding: 1.25rem;
border-bottom: 0 solid #e9ecef;
border-top-left-radius: .4375rem;
border-top-right-radius: .4375rem;
align-items: flex-start;
justify-content: space-between;
}
.modal-header .close
{
margin: -1.25rem -1.25rem -1.25rem auto;
padding: 1.25rem;
}
.modal-title
{
line-height: 1.1;
margin-bottom: 0;
}
.modal-body
{
position: relative;
padding: 1.5rem;
flex: 1 1 auto;
}
.modal-footer
{
display: flex;
padding: 1.5rem;
border-top: 0 solid #e9ecef;
align-items: center;
justify-content: flex-end;
}
.modal-footer > :not(:first-child)
{
margin-left: .25rem;
}
.modal-footer > :not(:last-child)
{
margin-right: .25rem;
}
.modal-scrollbar-measure
{
position: absolute;
top: -9999px;
overflow: scroll;
width: 50px;
height: 50px;
}
@media (min-width: 576px)
{
.modal-dialog
{
max-width: 500px;
margin: 1.75rem auto;
}
.modal-dialog-centered
{
min-height: calc(100% - (1.75rem * 2));
}
.modal-dialog-centered::before
{
height: calc(100vh - (1.75rem * 2));
}
.modal-content
{
box-shadow: 0 15px 35px rgba(50, 50, 93, .2), 0 5px 15px rgba(0, 0, 0, .17);
}
.modal-sm
{
max-width: 380px;
}
}
@media (min-width: 992px)
{
.modal-lg
{
max-width: 800px;
}
}
.tooltip
{
font-family: Open Sans, sans-serif;
font-size: .875rem;
font-weight: 400;
font-style: normal;
line-height: 1.5;
position: absolute;
z-index: 1070;
display: block;
margin: 0;
text-align: left;
text-align: start;
white-space: normal;
text-decoration: none;
letter-spacing: normal;
word-spacing: normal;
text-transform: none;
word-wrap: break-word;
word-break: normal;
opacity: 0;
text-shadow: none;
line-break: auto;
}
.tooltip.show
{
opacity: .9;
}
.tooltip .arrow
{
position: absolute;
display: block;
width: .8rem;
height: .4rem;
}
.tooltip .arrow::before
{
position: absolute;
content: '';
border-style: solid;
border-color: transparent;
}
.bs-tooltip-top,
.bs-tooltip-auto[x-placement^='top']
{
padding: .4rem 0;
}
.bs-tooltip-top .arrow,
.bs-tooltip-auto[x-placement^='top'] .arrow
{
bottom: 0;
}
.bs-tooltip-top .arrow::before,
.bs-tooltip-auto[x-placement^='top'] .arrow::before
{
top: 0;
border-width: .4rem .4rem 0;
border-top-color: #000;
}
.bs-tooltip-right,
.bs-tooltip-auto[x-placement^='right']
{
padding: 0 .4rem;
}
.bs-tooltip-right .arrow,
.bs-tooltip-auto[x-placement^='right'] .arrow
{
left: 0;
width: .4rem;
height: .8rem;
}
.bs-tooltip-right .arrow::before,
.bs-tooltip-auto[x-placement^='right'] .arrow::before
{
right: 0;
border-width: .4rem .4rem .4rem 0;
border-right-color: #000;
}
.bs-tooltip-bottom,
.bs-tooltip-auto[x-placement^='bottom']
{
padding: .4rem 0;
}
.bs-tooltip-bottom .arrow,
.bs-tooltip-auto[x-placement^='bottom'] .arrow
{
top: 0;
}
.bs-tooltip-bottom .arrow::before,
.bs-tooltip-auto[x-placement^='bottom'] .arrow::before
{
bottom: 0;
border-width: 0 .4rem .4rem;
border-bottom-color: #000;
}
.bs-tooltip-left,
.bs-tooltip-auto[x-placement^='left']
{
padding: 0 .4rem;
}
.bs-tooltip-left .arrow,
.bs-tooltip-auto[x-placement^='left'] .arrow
{
right: 0;
width: .4rem;
height: .8rem;
}
.bs-tooltip-left .arrow::before,
.bs-tooltip-auto[x-placement^='left'] .arrow::before
{
left: 0;
border-width: .4rem 0 .4rem .4rem;
border-left-color: #000;
}
.tooltip-inner
{
max-width: 200px;
padding: .25rem .5rem;
text-align: center;
color: #fff;
border-radius: .375rem;
background-color: #000;
}
.popover
{
font-family: Open Sans, sans-serif;
font-size: .875rem;
font-weight: 400;
font-style: normal;
line-height: 1.5;
position: absolute;
z-index: 1060;
top: 0;
left: 0;
display: block;
max-width: 276px;
text-align: left;
text-align: start;
white-space: normal;
text-decoration: none;
letter-spacing: normal;
word-spacing: normal;
text-transform: none;
word-wrap: break-word;
word-break: normal;
border: 1px solid rgba(0, 0, 0, .05);
border-radius: .4375rem;
background-color: #fff;
background-clip: padding-box;
box-shadow: 0 .5rem 2rem 0 rgba(0, 0, 0, .2);
text-shadow: none;
line-break: auto;
}
.popover .arrow
{
position: absolute;
display: block;
width: 1.5rem;
height: .75rem;
margin: 0 .4375rem;
}
.popover .arrow::before,
.popover .arrow::after
{
position: absolute;
display: block;
content: '';
border-style: solid;
border-color: transparent;
}
.bs-popover-top,
.bs-popover-auto[x-placement^='top']
{
margin-bottom: .75rem;
}
.bs-popover-top .arrow,
.bs-popover-auto[x-placement^='top'] .arrow
{
bottom: calc((.75rem + 1px) * -1);
}
.bs-popover-top .arrow::before,
.bs-popover-auto[x-placement^='top'] .arrow::before,
.bs-popover-top .arrow::after,
.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-width: .75rem .75rem 0;
}
.bs-popover-top .arrow::before,
.bs-popover-auto[x-placement^='top'] .arrow::before
{
bottom: 0;
border-top-color: transparent;
}
.bs-popover-top .arrow::after,
.bs-popover-auto[x-placement^='top'] .arrow::after
{
bottom: 1px;
border-top-color: #fff;
}
.bs-popover-right,
.bs-popover-auto[x-placement^='right']
{
margin-left: .75rem;
}
.bs-popover-right .arrow,
.bs-popover-auto[x-placement^='right'] .arrow
{
left: calc((.75rem + 1px) * -1);
width: .75rem;
height: 1.5rem;
margin: .4375rem 0;
}
.bs-popover-right .arrow::before,
.bs-popover-auto[x-placement^='right'] .arrow::before,
.bs-popover-right .arrow::after,
.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-width: .75rem .75rem .75rem 0;
}
.bs-popover-right .arrow::before,
.bs-popover-auto[x-placement^='right'] .arrow::before
{
left: 0;
border-right-color: transparent;
}
.bs-popover-right .arrow::after,
.bs-popover-auto[x-placement^='right'] .arrow::after
{
left: 1px;
border-right-color: #fff;
}
.bs-popover-bottom,
.bs-popover-auto[x-placement^='bottom']
{
margin-top: .75rem;
}
.bs-popover-bottom .arrow,
.bs-popover-auto[x-placement^='bottom'] .arrow
{
top: calc((.75rem + 1px) * -1);
}
.bs-popover-bottom .arrow::before,
.bs-popover-auto[x-placement^='bottom'] .arrow::before,
.bs-popover-bottom .arrow::after,
.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-width: 0 .75rem .75rem .75rem;
}
.bs-popover-bottom .arrow::before,
.bs-popover-auto[x-placement^='bottom'] .arrow::before
{
top: 0;
border-bottom-color: transparent;
}
.bs-popover-bottom .arrow::after,
.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
top: 1px;
border-bottom-color: #fff;
}
.bs-popover-bottom .popover-header::before,
.bs-popover-auto[x-placement^='bottom'] .popover-header::before
{
position: absolute;
top: 0;
left: 50%;
display: block;
width: 1.5rem;
margin-left: -.75rem;
content: '';
border-bottom: 1px solid #fff;
}
.bs-popover-left,
.bs-popover-auto[x-placement^='left']
{
margin-right: .75rem;
}
.bs-popover-left .arrow,
.bs-popover-auto[x-placement^='left'] .arrow
{
right: calc((.75rem + 1px) * -1);
width: .75rem;
height: 1.5rem;
margin: .4375rem 0;
}
.bs-popover-left .arrow::before,
.bs-popover-auto[x-placement^='left'] .arrow::before,
.bs-popover-left .arrow::after,
.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-width: .75rem 0 .75rem .75rem;
}
.bs-popover-left .arrow::before,
.bs-popover-auto[x-placement^='left'] .arrow::before
{
right: 0;
border-left-color: transparent;
}
.bs-popover-left .arrow::after,
.bs-popover-auto[x-placement^='left'] .arrow::after
{
right: 1px;
border-left-color: #fff;
}
.popover-header
{
font-size: 1rem;
margin-bottom: 0;
padding: .5rem .95rem;
color: #32325d;
border-bottom: 1px solid #f2f2f2;
border-top-left-radius: calc(.4375rem - 1px);
border-top-right-radius: calc(.4375rem - 1px);
background-color: #fff;
}
.popover-header:empty
{
display: none;
}
.popover-body
{
padding: .5rem .95rem;
color: #525f7f;
}
.carousel
{
position: relative;
}
.carousel-inner
{
position: relative;
overflow: hidden;
width: 100%;
}
.carousel-item
{
position: relative;
display: none;
width: 100%;
align-items: center;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
perspective: 1000px;
}
.carousel-item.active,
.carousel-item-next,
.carousel-item-prev
{
display: block;
transition: transform .6s ease;
}
@media screen and (prefers-reduced-motion: reduce)
{
.carousel-item.active,
.carousel-item-next,
.carousel-item-prev
{
transition: none;
}
}
.carousel-item-next,
.carousel-item-prev
{
position: absolute;
top: 0;
}
.carousel-item-next.carousel-item-left,
.carousel-item-prev.carousel-item-right
{
transform: translateX(0);
}
@supports (transform-style: preserve-3d)
{
.carousel-item-next.carousel-item-left,
.carousel-item-prev.carousel-item-right
{
transform: translate3d(0, 0, 0);
}
}
.carousel-item-next,
.active.carousel-item-right
{
transform: translateX(100%);
}
@supports (transform-style: preserve-3d)
{
.carousel-item-next,
.active.carousel-item-right
{
transform: translate3d(100%, 0, 0);
}
}
.carousel-item-prev,
.active.carousel-item-left
{
transform: translateX(-100%);
}
@supports (transform-style: preserve-3d)
{
.carousel-item-prev,
.active.carousel-item-left
{
transform: translate3d(-100%, 0, 0);
}
}
.carousel-fade .carousel-item
{
transition-duration: .6s;
transition-property: opacity;
opacity: 0;
}
.carousel-fade .carousel-item.active,
.carousel-fade .carousel-item-next.carousel-item-left,
.carousel-fade .carousel-item-prev.carousel-item-right
{
opacity: 1;
}
.carousel-fade .active.carousel-item-left,
.carousel-fade .active.carousel-item-right
{
opacity: 0;
}
.carousel-fade .carousel-item-next,
.carousel-fade .carousel-item-prev,
.carousel-fade .carousel-item.active,
.carousel-fade .active.carousel-item-left,
.carousel-fade .active.carousel-item-prev
{
transform: translateX(0);
}
@supports (transform-style: preserve-3d)
{
.carousel-fade .carousel-item-next,
.carousel-fade .carousel-item-prev,
.carousel-fade .carousel-item.active,
.carousel-fade .active.carousel-item-left,
.carousel-fade .active.carousel-item-prev
{
transform: translate3d(0, 0, 0);
}
}
.carousel-control-prev,
.carousel-control-next
{
position: absolute;
top: 0;
bottom: 0;
display: flex;
width: 15%;
text-align: center;
opacity: .5;
color: #fff;
align-items: center;
justify-content: center;
}
.carousel-control-prev:hover,
.carousel-control-prev:focus,
.carousel-control-next:hover,
.carousel-control-next:focus
{
text-decoration: none;
opacity: .9;
color: #fff;
outline: 0;
}
.carousel-control-prev
{
left: 0;
}
.carousel-control-next
{
right: 0;
}
.carousel-control-prev-icon,
.carousel-control-next-icon
{
display: inline-block;
width: 20px;
height: 20px;
background: transparent no-repeat center center;
background-size: 100% 100%;
}
.carousel-control-prev-icon
{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' fill=\'%23fff\' viewBox=\'0 0 8 8\'%3E%3Cpath d=\'M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z\'/%3E%3C/svg%3E');
}
.carousel-control-next-icon
{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' fill=\'%23fff\' viewBox=\'0 0 8 8\'%3E%3Cpath d=\'M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z\'/%3E%3C/svg%3E');
}
.carousel-indicators
{
position: absolute;
z-index: 15;
right: 0;
bottom: 10px;
left: 0;
display: flex;
margin-right: 15%;
margin-left: 15%;
padding-left: 0;
list-style: none;
justify-content: center;
}
.carousel-indicators li
{
position: relative;
width: 30px;
height: 3px;
margin-right: 3px;
margin-left: 3px;
cursor: pointer;
text-indent: -999px;
background-color: rgba(255, 255, 255, .5);
flex: 0 1 auto;
}
.carousel-indicators li::before
{
position: absolute;
top: -10px;
left: 0;
display: inline-block;
width: 100%;
height: 10px;
content: '';
}
.carousel-indicators li::after
{
position: absolute;
bottom: -10px;
left: 0;
display: inline-block;
width: 100%;
height: 10px;
content: '';
}
.carousel-indicators .active
{
background-color: #fff;
}
.carousel-caption
{
position: absolute;
z-index: 10;
right: 15%;
bottom: 20px;
left: 15%;
padding-top: 20px;
padding-bottom: 20px;
text-align: center;
color: #fff;
}
.align-baseline
{
vertical-align: baseline !important;
}
.align-top
{
vertical-align: top !important;
}
.align-middle
{
vertical-align: middle !important;
}
.align-bottom
{
vertical-align: bottom !important;
}
.align-text-bottom
{
vertical-align: text-bottom !important;
}
.align-text-top
{
vertical-align: text-top !important;
}
.bg-primary
{
background-color: #5e72e4 !important;
}
a.bg-primary:hover,
a.bg-primary:focus,
button.bg-primary:hover,
button.bg-primary:focus
{
background-color: #324cdd !important;
}
.bg-secondary
{
background-color: #f7fafc !important;
}
a.bg-secondary:hover,
a.bg-secondary:focus,
button.bg-secondary:hover,
button.bg-secondary:focus
{
background-color: #d2e3ee !important;
}
.bg-success
{
background-color: #2dce89 !important;
}
a.bg-success:hover,
a.bg-success:focus,
button.bg-success:hover,
button.bg-success:focus
{
background-color: #24a46d !important;
}
.bg-info
{
background-color: #11cdef !important;
}
a.bg-info:hover,
a.bg-info:focus,
button.bg-info:hover,
button.bg-info:focus
{
background-color: #0da5c0 !important;
}
.bg-warning
{
background-color: #fb6340 !important;
}
a.bg-warning:hover,
a.bg-warning:focus,
button.bg-warning:hover,
button.bg-warning:focus
{
background-color: #fa3a0e !important;
}
.bg-danger
{
background-color: #f5365c !important;
}
a.bg-danger:hover,
a.bg-danger:focus,
button.bg-danger:hover,
button.bg-danger:focus
{
background-color: #ec0c38 !important;
}
.bg-light
{
background-color: #adb5bd !important;
}
a.bg-light:hover,
a.bg-light:focus,
button.bg-light:hover,
button.bg-light:focus
{
background-color: #919ca6 !important;
}
.bg-dark
{
background-color: #212529 !important;
}
a.bg-dark:hover,
a.bg-dark:focus,
button.bg-dark:hover,
button.bg-dark:focus
{
background-color: #0a0c0d !important;
}
.bg-default
{
background-color: #172b4d !important;
}
a.bg-default:hover,
a.bg-default:focus,
button.bg-default:hover,
button.bg-default:focus
{
background-color: #0b1526 !important;
}
.bg-white
{
background-color: #fff !important;
}
a.bg-white:hover,
a.bg-white:focus,
button.bg-white:hover,
button.bg-white:focus
{
background-color: #e6e6e6 !important;
}
.bg-neutral
{
background-color: #fff !important;
}
a.bg-neutral:hover,
a.bg-neutral:focus,
button.bg-neutral:hover,
button.bg-neutral:focus
{
background-color: #e6e6e6 !important;
}
.bg-darker
{
background-color: black !important;
}
a.bg-darker:hover,
a.bg-darker:focus,
button.bg-darker:hover,
button.bg-darker:focus
{
background-color: black !important;
}
.bg-white
{
background-color: #fff !important;
}
.bg-transparent
{
background-color: transparent !important;
}
.border
{
border: 1px solid #e9ecef !important;
}
.border-top
{
border-top: 1px solid #e9ecef !important;
}
.border-right
{
border-right: 1px solid #e9ecef !important;
}
.border-bottom
{
border-bottom: 1px solid #e9ecef !important;
}
.border-left
{
border-left: 1px solid #e9ecef !important;
}
.border-0
{
border: 0 !important;
}
.border-top-0
{
border-top: 0 !important;
}
.border-right-0
{
border-right: 0 !important;
}
.border-bottom-0
{
border-bottom: 0 !important;
}
.border-left-0
{
border-left: 0 !important;
}
.border-primary
{
border-color: #5e72e4 !important;
}
.border-secondary
{
border-color: #f7fafc !important;
}
.border-success
{
border-color: #2dce89 !important;
}
.border-info
{
border-color: #11cdef !important;
}
.border-warning
{
border-color: #fb6340 !important;
}
.border-danger
{
border-color: #f5365c !important;
}
.border-light
{
border-color: #adb5bd !important;
}
.border-dark
{
border-color: #212529 !important;
}
.border-default
{
border-color: #172b4d !important;
}
.border-white
{
border-color: #fff !important;
}
.border-neutral
{
border-color: #fff !important;
}
.border-darker
{
border-color: black !important;
}
.border-white
{
border-color: #fff !important;
}
.rounded
{
border-radius: .375rem !important;
}
.rounded-top
{
border-top-left-radius: .375rem !important;
border-top-right-radius: .375rem !important;
}
.rounded-right
{
border-top-right-radius: .375rem !important;
border-bottom-right-radius: .375rem !important;
}
.rounded-bottom
{
border-bottom-right-radius: .375rem !important;
border-bottom-left-radius: .375rem !important;
}
.rounded-left
{
border-top-left-radius: .375rem !important;
border-bottom-left-radius: .375rem !important;
}
.rounded-circle
{
border-radius: 50% !important;
}
.rounded-0
{
border-radius: 0 !important;
}
.clearfix::after
{
display: block;
clear: both;
content: '';
}
.d-none
{
display: none !important;
}
.d-inline
{
display: inline !important;
}
.d-inline-block
{
display: inline-block !important;
}
.d-block
{
display: block !important;
}
.d-table
{
display: table !important;
}
.d-table-row
{
display: table-row !important;
}
.d-table-cell
{
display: table-cell !important;
}
.d-flex
{
display: flex !important;
}
.d-inline-flex
{
display: inline-flex !important;
}
@media (min-width: 576px)
{
.d-sm-none
{
display: none !important;
}
.d-sm-inline
{
display: inline !important;
}
.d-sm-inline-block
{
display: inline-block !important;
}
.d-sm-block
{
display: block !important;
}
.d-sm-table
{
display: table !important;
}
.d-sm-table-row
{
display: table-row !important;
}
.d-sm-table-cell
{
display: table-cell !important;
}
.d-sm-flex
{
display: flex !important;
}
.d-sm-inline-flex
{
display: inline-flex !important;
}
}
@media (min-width: 768px)
{
.d-md-none
{
display: none !important;
}
.d-md-inline
{
display: inline !important;
}
.d-md-inline-block
{
display: inline-block !important;
}
.d-md-block
{
display: block !important;
}
.d-md-table
{
display: table !important;
}
.d-md-table-row
{
display: table-row !important;
}
.d-md-table-cell
{
display: table-cell !important;
}
.d-md-flex
{
display: flex !important;
}
.d-md-inline-flex
{
display: inline-flex !important;
}
}
@media (min-width: 992px)
{
.d-lg-none
{
display: none !important;
}
.d-lg-inline
{
display: inline !important;
}
.d-lg-inline-block
{
display: inline-block !important;
}
.d-lg-block
{
display: block !important;
}
.d-lg-table
{
display: table !important;
}
.d-lg-table-row
{
display: table-row !important;
}
.d-lg-table-cell
{
display: table-cell !important;
}
.d-lg-flex
{
display: flex !important;
}
.d-lg-inline-flex
{
display: inline-flex !important;
}
}
@media (min-width: 1200px)
{
.d-xl-none
{
display: none !important;
}
.d-xl-inline
{
display: inline !important;
}
.d-xl-inline-block
{
display: inline-block !important;
}
.d-xl-block
{
display: block !important;
}
.d-xl-table
{
display: table !important;
}
.d-xl-table-row
{
display: table-row !important;
}
.d-xl-table-cell
{
display: table-cell !important;
}
.d-xl-flex
{
display: flex !important;
}
.d-xl-inline-flex
{
display: inline-flex !important;
}
}
@media print
{
.d-print-none
{
display: none !important;
}
.d-print-inline
{
display: inline !important;
}
.d-print-inline-block
{
display: inline-block !important;
}
.d-print-block
{
display: block !important;
}
.d-print-table
{
display: table !important;
}
.d-print-table-row
{
display: table-row !important;
}
.d-print-table-cell
{
display: table-cell !important;
}
.d-print-flex
{
display: flex !important;
}
.d-print-inline-flex
{
display: inline-flex !important;
}
}
.embed-responsive
{
position: relative;
display: block;
overflow: hidden;
width: 100%;
padding: 0;
}
.embed-responsive::before
{
display: block;
content: '';
}
.embed-responsive .embed-responsive-item,
.embed-responsive iframe,
.embed-responsive embed,
.embed-responsive object,
.embed-responsive video
{
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
.embed-responsive-21by9::before
{
padding-top: 42.85714%;
}
.embed-responsive-16by9::before
{
padding-top: 56.25%;
}
.embed-responsive-4by3::before
{
padding-top: 75%;
}
.embed-responsive-1by1::before
{
padding-top: 100%;
}
.flex-row
{
flex-direction: row !important;
}
.flex-column
{
flex-direction: column !important;
}
.flex-row-reverse
{
flex-direction: row-reverse !important;
}
.flex-column-reverse
{
flex-direction: column-reverse !important;
}
.flex-wrap
{
flex-wrap: wrap !important;
}
.flex-nowrap
{
flex-wrap: nowrap !important;
}
.flex-wrap-reverse
{
flex-wrap: wrap-reverse !important;
}
.flex-fill
{
flex: 1 1 auto !important;
}
.flex-grow-0
{
flex-grow: 0 !important;
}
.flex-grow-1
{
flex-grow: 1 !important;
}
.flex-shrink-0
{
flex-shrink: 0 !important;
}
.flex-shrink-1
{
flex-shrink: 1 !important;
}
.justify-content-start
{
justify-content: flex-start !important;
}
.justify-content-end
{
justify-content: flex-end !important;
}
.justify-content-center
{
justify-content: center !important;
}
.justify-content-between
{
justify-content: space-between !important;
}
.justify-content-around
{
justify-content: space-around !important;
}
.align-items-start
{
align-items: flex-start !important;
}
.align-items-end
{
align-items: flex-end !important;
}
.align-items-center
{
align-items: center !important;
}
.align-items-baseline
{
align-items: baseline !important;
}
.align-items-stretch
{
align-items: stretch !important;
}
.align-content-start
{
align-content: flex-start !important;
}
.align-content-end
{
align-content: flex-end !important;
}
.align-content-center
{
align-content: center !important;
}
.align-content-between
{
align-content: space-between !important;
}
.align-content-around
{
align-content: space-around !important;
}
.align-content-stretch
{
align-content: stretch !important;
}
.align-self-auto
{
align-self: auto !important;
}
.align-self-start
{
align-self: flex-start !important;
}
.align-self-end
{
align-self: flex-end !important;
}
.align-self-center
{
align-self: center !important;
}
.align-self-baseline
{
align-self: baseline !important;
}
.align-self-stretch
{
align-self: stretch !important;
}
@media (min-width: 576px)
{
.flex-sm-row
{
flex-direction: row !important;
}
.flex-sm-column
{
flex-direction: column !important;
}
.flex-sm-row-reverse
{
flex-direction: row-reverse !important;
}
.flex-sm-column-reverse
{
flex-direction: column-reverse !important;
}
.flex-sm-wrap
{
flex-wrap: wrap !important;
}
.flex-sm-nowrap
{
flex-wrap: nowrap !important;
}
.flex-sm-wrap-reverse
{
flex-wrap: wrap-reverse !important;
}
.flex-sm-fill
{
flex: 1 1 auto !important;
}
.flex-sm-grow-0
{
flex-grow: 0 !important;
}
.flex-sm-grow-1
{
flex-grow: 1 !important;
}
.flex-sm-shrink-0
{
flex-shrink: 0 !important;
}
.flex-sm-shrink-1
{
flex-shrink: 1 !important;
}
.justify-content-sm-start
{
justify-content: flex-start !important;
}
.justify-content-sm-end
{
justify-content: flex-end !important;
}
.justify-content-sm-center
{
justify-content: center !important;
}
.justify-content-sm-between
{
justify-content: space-between !important;
}
.justify-content-sm-around
{
justify-content: space-around !important;
}
.align-items-sm-start
{
align-items: flex-start !important;
}
.align-items-sm-end
{
align-items: flex-end !important;
}
.align-items-sm-center
{
align-items: center !important;
}
.align-items-sm-baseline
{
align-items: baseline !important;
}
.align-items-sm-stretch
{
align-items: stretch !important;
}
.align-content-sm-start
{
align-content: flex-start !important;
}
.align-content-sm-end
{
align-content: flex-end !important;
}
.align-content-sm-center
{
align-content: center !important;
}
.align-content-sm-between
{
align-content: space-between !important;
}
.align-content-sm-around
{
align-content: space-around !important;
}
.align-content-sm-stretch
{
align-content: stretch !important;
}
.align-self-sm-auto
{
align-self: auto !important;
}
.align-self-sm-start
{
align-self: flex-start !important;
}
.align-self-sm-end
{
align-self: flex-end !important;
}
.align-self-sm-center
{
align-self: center !important;
}
.align-self-sm-baseline
{
align-self: baseline !important;
}
.align-self-sm-stretch
{
align-self: stretch !important;
}
}
@media (min-width: 768px)
{
.flex-md-row
{
flex-direction: row !important;
}
.flex-md-column
{
flex-direction: column !important;
}
.flex-md-row-reverse
{
flex-direction: row-reverse !important;
}
.flex-md-column-reverse
{
flex-direction: column-reverse !important;
}
.flex-md-wrap
{
flex-wrap: wrap !important;
}
.flex-md-nowrap
{
flex-wrap: nowrap !important;
}
.flex-md-wrap-reverse
{
flex-wrap: wrap-reverse !important;
}
.flex-md-fill
{
flex: 1 1 auto !important;
}
.flex-md-grow-0
{
flex-grow: 0 !important;
}
.flex-md-grow-1
{
flex-grow: 1 !important;
}
.flex-md-shrink-0
{
flex-shrink: 0 !important;
}
.flex-md-shrink-1
{
flex-shrink: 1 !important;
}
.justify-content-md-start
{
justify-content: flex-start !important;
}
.justify-content-md-end
{
justify-content: flex-end !important;
}
.justify-content-md-center
{
justify-content: center !important;
}
.justify-content-md-between
{
justify-content: space-between !important;
}
.justify-content-md-around
{
justify-content: space-around !important;
}
.align-items-md-start
{
align-items: flex-start !important;
}
.align-items-md-end
{
align-items: flex-end !important;
}
.align-items-md-center
{
align-items: center !important;
}
.align-items-md-baseline
{
align-items: baseline !important;
}
.align-items-md-stretch
{
align-items: stretch !important;
}
.align-content-md-start
{
align-content: flex-start !important;
}
.align-content-md-end
{
align-content: flex-end !important;
}
.align-content-md-center
{
align-content: center !important;
}
.align-content-md-between
{
align-content: space-between !important;
}
.align-content-md-around
{
align-content: space-around !important;
}
.align-content-md-stretch
{
align-content: stretch !important;
}
.align-self-md-auto
{
align-self: auto !important;
}
.align-self-md-start
{
align-self: flex-start !important;
}
.align-self-md-end
{
align-self: flex-end !important;
}
.align-self-md-center
{
align-self: center !important;
}
.align-self-md-baseline
{
align-self: baseline !important;
}
.align-self-md-stretch
{
align-self: stretch !important;
}
}
@media (min-width: 992px)
{
.flex-lg-row
{
flex-direction: row !important;
}
.flex-lg-column
{
flex-direction: column !important;
}
.flex-lg-row-reverse
{
flex-direction: row-reverse !important;
}
.flex-lg-column-reverse
{
flex-direction: column-reverse !important;
}
.flex-lg-wrap
{
flex-wrap: wrap !important;
}
.flex-lg-nowrap
{
flex-wrap: nowrap !important;
}
.flex-lg-wrap-reverse
{
flex-wrap: wrap-reverse !important;
}
.flex-lg-fill
{
flex: 1 1 auto !important;
}
.flex-lg-grow-0
{
flex-grow: 0 !important;
}
.flex-lg-grow-1
{
flex-grow: 1 !important;
}
.flex-lg-shrink-0
{
flex-shrink: 0 !important;
}
.flex-lg-shrink-1
{
flex-shrink: 1 !important;
}
.justify-content-lg-start
{
justify-content: flex-start !important;
}
.justify-content-lg-end
{
justify-content: flex-end !important;
}
.justify-content-lg-center
{
justify-content: center !important;
}
.justify-content-lg-between
{
justify-content: space-between !important;
}
.justify-content-lg-around
{
justify-content: space-around !important;
}
.align-items-lg-start
{
align-items: flex-start !important;
}
.align-items-lg-end
{
align-items: flex-end !important;
}
.align-items-lg-center
{
align-items: center !important;
}
.align-items-lg-baseline
{
align-items: baseline !important;
}
.align-items-lg-stretch
{
align-items: stretch !important;
}
.align-content-lg-start
{
align-content: flex-start !important;
}
.align-content-lg-end
{
align-content: flex-end !important;
}
.align-content-lg-center
{
align-content: center !important;
}
.align-content-lg-between
{
align-content: space-between !important;
}
.align-content-lg-around
{
align-content: space-around !important;
}
.align-content-lg-stretch
{
align-content: stretch !important;
}
.align-self-lg-auto
{
align-self: auto !important;
}
.align-self-lg-start
{
align-self: flex-start !important;
}
.align-self-lg-end
{
align-self: flex-end !important;
}
.align-self-lg-center
{
align-self: center !important;
}
.align-self-lg-baseline
{
align-self: baseline !important;
}
.align-self-lg-stretch
{
align-self: stretch !important;
}
}
@media (min-width: 1200px)
{
.flex-xl-row
{
flex-direction: row !important;
}
.flex-xl-column
{
flex-direction: column !important;
}
.flex-xl-row-reverse
{
flex-direction: row-reverse !important;
}
.flex-xl-column-reverse
{
flex-direction: column-reverse !important;
}
.flex-xl-wrap
{
flex-wrap: wrap !important;
}
.flex-xl-nowrap
{
flex-wrap: nowrap !important;
}
.flex-xl-wrap-reverse
{
flex-wrap: wrap-reverse !important;
}
.flex-xl-fill
{
flex: 1 1 auto !important;
}
.flex-xl-grow-0
{
flex-grow: 0 !important;
}
.flex-xl-grow-1
{
flex-grow: 1 !important;
}
.flex-xl-shrink-0
{
flex-shrink: 0 !important;
}
.flex-xl-shrink-1
{
flex-shrink: 1 !important;
}
.justify-content-xl-start
{
justify-content: flex-start !important;
}
.justify-content-xl-end
{
justify-content: flex-end !important;
}
.justify-content-xl-center
{
justify-content: center !important;
}
.justify-content-xl-between
{
justify-content: space-between !important;
}
.justify-content-xl-around
{
justify-content: space-around !important;
}
.align-items-xl-start
{
align-items: flex-start !important;
}
.align-items-xl-end
{
align-items: flex-end !important;
}
.align-items-xl-center
{
align-items: center !important;
}
.align-items-xl-baseline
{
align-items: baseline !important;
}
.align-items-xl-stretch
{
align-items: stretch !important;
}
.align-content-xl-start
{
align-content: flex-start !important;
}
.align-content-xl-end
{
align-content: flex-end !important;
}
.align-content-xl-center
{
align-content: center !important;
}
.align-content-xl-between
{
align-content: space-between !important;
}
.align-content-xl-around
{
align-content: space-around !important;
}
.align-content-xl-stretch
{
align-content: stretch !important;
}
.align-self-xl-auto
{
align-self: auto !important;
}
.align-self-xl-start
{
align-self: flex-start !important;
}
.align-self-xl-end
{
align-self: flex-end !important;
}
.align-self-xl-center
{
align-self: center !important;
}
.align-self-xl-baseline
{
align-self: baseline !important;
}
.align-self-xl-stretch
{
align-self: stretch !important;
}
}
.float-left
{
float: left !important;
}
.float-right
{
float: right !important;
}
.float-none
{
float: none !important;
}
@media (min-width: 576px)
{
.float-sm-left
{
float: left !important;
}
.float-sm-right
{
float: right !important;
}
.float-sm-none
{
float: none !important;
}
}
@media (min-width: 768px)
{
.float-md-left
{
float: left !important;
}
.float-md-right
{
float: right !important;
}
.float-md-none
{
float: none !important;
}
}
@media (min-width: 992px)
{
.float-lg-left
{
float: left !important;
}
.float-lg-right
{
float: right !important;
}
.float-lg-none
{
float: none !important;
}
}
@media (min-width: 1200px)
{
.float-xl-left
{
float: left !important;
}
.float-xl-right
{
float: right !important;
}
.float-xl-none
{
float: none !important;
}
}
.position-static
{
position: static !important;
}
.position-relative
{
position: relative !important;
}
.position-absolute
{
position: absolute !important;
}
.position-fixed
{
position: fixed !important;
}
.position-sticky
{
position: -webkit-sticky !important;
position: sticky !important;
}
.fixed-top
{
position: fixed;
z-index: 1030;
top: 0;
right: 0;
left: 0;
}
.fixed-bottom
{
position: fixed;
z-index: 1030;
right: 0;
bottom: 0;
left: 0;
}
@supports ((position: -webkit-sticky) or (position: sticky))
{
.sticky-top
{
position: -webkit-sticky;
position: sticky;
z-index: 1020;
top: 0;
}
}
.sr-only
{
position: absolute;
overflow: hidden;
clip: rect(0, 0, 0, 0);
width: 1px;
height: 1px;
padding: 0;
white-space: nowrap;
border: 0;
}
.sr-only-focusable:active,
.sr-only-focusable:focus
{
position: static;
overflow: visible;
clip: auto;
width: auto;
height: auto;
white-space: normal;
}
.shadow-sm
{
box-shadow: 0 0 .5rem rgba(136, 152, 170, .075) !important;
}
.shadow,
.card-profile-image img
{
box-shadow: 0 0 2rem 0 rgba(136, 152, 170, .15) !important;
}
.shadow-lg
{
box-shadow: 0 0 3rem rgba(136, 152, 170, .175) !important;
}
.shadow-none
{
box-shadow: none !important;
}
.w-25
{
width: 25% !important;
}
.w-50
{
width: 50% !important;
}
.w-75
{
width: 75% !important;
}
.w-100
{
width: 100% !important;
}
.w-auto
{
width: auto !important;
}
.h-25
{
height: 25% !important;
}
.h-50
{
height: 50% !important;
}
.h-75
{
height: 75% !important;
}
.h-100
{
height: 100% !important;
}
.h-auto
{
height: auto !important;
}
.mw-100
{
max-width: 100% !important;
}
.mh-100
{
max-height: 100% !important;
}
.m-0
{
margin: 0 !important;
}
.mt-0,
.my-0
{
margin-top: 0 !important;
}
.mr-0,
.mx-0
{
margin-right: 0 !important;
}
.mb-0,
.my-0
{
margin-bottom: 0 !important;
}
.ml-0,
.mx-0
{
margin-left: 0 !important;
}
.m-1
{
margin: .25rem !important;
}
.mt-1,
.my-1
{
margin-top: .25rem !important;
}
.mr-1,
.mx-1
{
margin-right: .25rem !important;
}
.mb-1,
.my-1
{
margin-bottom: .25rem !important;
}
.ml-1,
.mx-1
{
margin-left: .25rem !important;
}
.m-2
{
margin: .5rem !important;
}
.mt-2,
.my-2
{
margin-top: .5rem !important;
}
.mr-2,
.mx-2
{
margin-right: .5rem !important;
}
.mb-2,
.my-2
{
margin-bottom: .5rem !important;
}
.ml-2,
.mx-2
{
margin-left: .5rem !important;
}
.m-3
{
margin: 1rem !important;
}
.mt-3,
.my-3
{
margin-top: 1rem !important;
}
.mr-3,
.mx-3
{
margin-right: 1rem !important;
}
.mb-3,
.my-3
{
margin-bottom: 1rem !important;
}
.ml-3,
.mx-3
{
margin-left: 1rem !important;
}
.m-4
{
margin: 1.5rem !important;
}
.mt-4,
.my-4
{
margin-top: 1.5rem !important;
}
.mr-4,
.mx-4
{
margin-right: 1.5rem !important;
}
.mb-4,
.my-4
{
margin-bottom: 1.5rem !important;
}
.ml-4,
.mx-4
{
margin-left: 1.5rem !important;
}
.m-5
{
margin: 3rem !important;
}
.mt-5,
.my-5
{
margin-top: 3rem !important;
}
.mr-5,
.mx-5
{
margin-right: 3rem !important;
}
.mb-5,
.my-5
{
margin-bottom: 3rem !important;
}
.ml-5,
.mx-5
{
margin-left: 3rem !important;
}
.m--9
{
margin: -10rem !important;
}
.mt--9,
.my--9
{
margin-top: -10rem !important;
}
.mr--9,
.mx--9
{
margin-right: -10rem !important;
}
.mb--9,
.my--9
{
margin-bottom: -10rem !important;
}
.ml--9,
.mx--9
{
margin-left: -10rem !important;
}
.m--8
{
margin: -8rem !important;
}
.mt--8,
.my--8
{
margin-top: -8rem !important;
}
.mr--8,
.mx--8
{
margin-right: -8rem !important;
}
.mb--8,
.my--8
{
margin-bottom: -8rem !important;
}
.ml--8,
.mx--8
{
margin-left: -8rem !important;
}
.m--7
{
margin: -6rem !important;
}
.mt--7,
.my--7
{
margin-top: -6rem !important;
}
.mr--7,
.mx--7
{
margin-right: -6rem !important;
}
.mb--7,
.my--7
{
margin-bottom: -6rem !important;
}
.ml--7,
.mx--7
{
margin-left: -6rem !important;
}
.m--6
{
margin: -4.5rem !important;
}
.mt--6,
.my--6
{
margin-top: -4.5rem !important;
}
.mr--6,
.mx--6
{
margin-right: -4.5rem !important;
}
.mb--6,
.my--6
{
margin-bottom: -4.5rem !important;
}
.ml--6,
.mx--6
{
margin-left: -4.5rem !important;
}
.m--5
{
margin: -3rem !important;
}
.mt--5,
.my--5
{
margin-top: -3rem !important;
}
.mr--5,
.mx--5
{
margin-right: -3rem !important;
}
.mb--5,
.my--5
{
margin-bottom: -3rem !important;
}
.ml--5,
.mx--5
{
margin-left: -3rem !important;
}
.m--4
{
margin: -1.5rem !important;
}
.mt--4,
.my--4
{
margin-top: -1.5rem !important;
}
.mr--4,
.mx--4
{
margin-right: -1.5rem !important;
}
.mb--4,
.my--4
{
margin-bottom: -1.5rem !important;
}
.ml--4,
.mx--4
{
margin-left: -1.5rem !important;
}
.m--3
{
margin: -1rem !important;
}
.mt--3,
.my--3
{
margin-top: -1rem !important;
}
.mr--3,
.mx--3
{
margin-right: -1rem !important;
}
.mb--3,
.my--3
{
margin-bottom: -1rem !important;
}
.ml--3,
.mx--3
{
margin-left: -1rem !important;
}
.m--2
{
margin: -.5rem !important;
}
.mt--2,
.my--2
{
margin-top: -.5rem !important;
}
.mr--2,
.mx--2
{
margin-right: -.5rem !important;
}
.mb--2,
.my--2
{
margin-bottom: -.5rem !important;
}
.ml--2,
.mx--2
{
margin-left: -.5rem !important;
}
.m--1
{
margin: -.25rem !important;
}
.mt--1,
.my--1
{
margin-top: -.25rem !important;
}
.mr--1,
.mx--1
{
margin-right: -.25rem !important;
}
.mb--1,
.my--1
{
margin-bottom: -.25rem !important;
}
.ml--1,
.mx--1
{
margin-left: -.25rem !important;
}
.m-6
{
margin: 4.5rem !important;
}
.mt-6,
.my-6
{
margin-top: 4.5rem !important;
}
.mr-6,
.mx-6
{
margin-right: 4.5rem !important;
}
.mb-6,
.my-6
{
margin-bottom: 4.5rem !important;
}
.ml-6,
.mx-6
{
margin-left: 4.5rem !important;
}
.m-7
{
margin: 6rem !important;
}
.mt-7,
.my-7
{
margin-top: 6rem !important;
}
.mr-7,
.mx-7
{
margin-right: 6rem !important;
}
.mb-7,
.my-7
{
margin-bottom: 6rem !important;
}
.ml-7,
.mx-7
{
margin-left: 6rem !important;
}
.m-8
{
margin: 8rem !important;
}
.mt-8,
.my-8
{
margin-top: 8rem !important;
}
.mr-8,
.mx-8
{
margin-right: 8rem !important;
}
.mb-8,
.my-8
{
margin-bottom: 8rem !important;
}
.ml-8,
.mx-8
{
margin-left: 8rem !important;
}
.m-9
{
margin: 10rem !important;
}
.mt-9,
.my-9
{
margin-top: 10rem !important;
}
.mr-9,
.mx-9
{
margin-right: 10rem !important;
}
.mb-9,
.my-9
{
margin-bottom: 10rem !important;
}
.ml-9,
.mx-9
{
margin-left: 10rem !important;
}
.p-0
{
padding: 0 !important;
}
.pt-0,
.py-0
{
padding-top: 0 !important;
}
.pr-0,
.px-0
{
padding-right: 0 !important;
}
.pb-0,
.py-0
{
padding-bottom: 0 !important;
}
.pl-0,
.px-0
{
padding-left: 0 !important;
}
.p-1
{
padding: .25rem !important;
}
.pt-1,
.py-1
{
padding-top: .25rem !important;
}
.pr-1,
.px-1
{
padding-right: .25rem !important;
}
.pb-1,
.py-1
{
padding-bottom: .25rem !important;
}
.pl-1,
.px-1
{
padding-left: .25rem !important;
}
.p-2
{
padding: .5rem !important;
}
.pt-2,
.py-2
{
padding-top: .5rem !important;
}
.pr-2,
.px-2
{
padding-right: .5rem !important;
}
.pb-2,
.py-2
{
padding-bottom: .5rem !important;
}
.pl-2,
.px-2
{
padding-left: .5rem !important;
}
.p-3
{
padding: 1rem !important;
}
.pt-3,
.py-3
{
padding-top: 1rem !important;
}
.pr-3,
.px-3
{
padding-right: 1rem !important;
}
.pb-3,
.py-3
{
padding-bottom: 1rem !important;
}
.pl-3,
.px-3
{
padding-left: 1rem !important;
}
.p-4
{
padding: 1.5rem !important;
}
.pt-4,
.py-4
{
padding-top: 1.5rem !important;
}
.pr-4,
.px-4
{
padding-right: 1.5rem !important;
}
.pb-4,
.py-4
{
padding-bottom: 1.5rem !important;
}
.pl-4,
.px-4
{
padding-left: 1.5rem !important;
}
.p-5
{
padding: 3rem !important;
}
.pt-5,
.py-5
{
padding-top: 3rem !important;
}
.pr-5,
.px-5
{
padding-right: 3rem !important;
}
.pb-5,
.py-5
{
padding-bottom: 3rem !important;
}
.pl-5,
.px-5
{
padding-left: 3rem !important;
}
.p--9
{
padding: -10rem !important;
}
.pt--9,
.py--9
{
padding-top: -10rem !important;
}
.pr--9,
.px--9
{
padding-right: -10rem !important;
}
.pb--9,
.py--9
{
padding-bottom: -10rem !important;
}
.pl--9,
.px--9
{
padding-left: -10rem !important;
}
.p--8
{
padding: -8rem !important;
}
.pt--8,
.py--8
{
padding-top: -8rem !important;
}
.pr--8,
.px--8
{
padding-right: -8rem !important;
}
.pb--8,
.py--8
{
padding-bottom: -8rem !important;
}
.pl--8,
.px--8
{
padding-left: -8rem !important;
}
.p--7
{
padding: -6rem !important;
}
.pt--7,
.py--7
{
padding-top: -6rem !important;
}
.pr--7,
.px--7
{
padding-right: -6rem !important;
}
.pb--7,
.py--7
{
padding-bottom: -6rem !important;
}
.pl--7,
.px--7
{
padding-left: -6rem !important;
}
.p--6
{
padding: -4.5rem !important;
}
.pt--6,
.py--6
{
padding-top: -4.5rem !important;
}
.pr--6,
.px--6
{
padding-right: -4.5rem !important;
}
.pb--6,
.py--6
{
padding-bottom: -4.5rem !important;
}
.pl--6,
.px--6
{
padding-left: -4.5rem !important;
}
.p--5
{
padding: -3rem !important;
}
.pt--5,
.py--5
{
padding-top: -3rem !important;
}
.pr--5,
.px--5
{
padding-right: -3rem !important;
}
.pb--5,
.py--5
{
padding-bottom: -3rem !important;
}
.pl--5,
.px--5
{
padding-left: -3rem !important;
}
.p--4
{
padding: -1.5rem !important;
}
.pt--4,
.py--4
{
padding-top: -1.5rem !important;
}
.pr--4,
.px--4
{
padding-right: -1.5rem !important;
}
.pb--4,
.py--4
{
padding-bottom: -1.5rem !important;
}
.pl--4,
.px--4
{
padding-left: -1.5rem !important;
}
.p--3
{
padding: -1rem !important;
}
.pt--3,
.py--3
{
padding-top: -1rem !important;
}
.pr--3,
.px--3
{
padding-right: -1rem !important;
}
.pb--3,
.py--3
{
padding-bottom: -1rem !important;
}
.pl--3,
.px--3
{
padding-left: -1rem !important;
}
.p--2
{
padding: -.5rem !important;
}
.pt--2,
.py--2
{
padding-top: -.5rem !important;
}
.pr--2,
.px--2
{
padding-right: -.5rem !important;
}
.pb--2,
.py--2
{
padding-bottom: -.5rem !important;
}
.pl--2,
.px--2
{
padding-left: -.5rem !important;
}
.p--1
{
padding: -.25rem !important;
}
.pt--1,
.py--1
{
padding-top: -.25rem !important;
}
.pr--1,
.px--1
{
padding-right: -.25rem !important;
}
.pb--1,
.py--1
{
padding-bottom: -.25rem !important;
}
.pl--1,
.px--1
{
padding-left: -.25rem !important;
}
.p-6
{
padding: 4.5rem !important;
}
.pt-6,
.py-6
{
padding-top: 4.5rem !important;
}
.pr-6,
.px-6
{
padding-right: 4.5rem !important;
}
.pb-6,
.py-6
{
padding-bottom: 4.5rem !important;
}
.pl-6,
.px-6
{
padding-left: 4.5rem !important;
}
.p-7
{
padding: 6rem !important;
}
.pt-7,
.py-7
{
padding-top: 6rem !important;
}
.pr-7,
.px-7
{
padding-right: 6rem !important;
}
.pb-7,
.py-7
{
padding-bottom: 6rem !important;
}
.pl-7,
.px-7
{
padding-left: 6rem !important;
}
.p-8
{
padding: 8rem !important;
}
.pt-8,
.py-8
{
padding-top: 8rem !important;
}
.pr-8,
.px-8
{
padding-right: 8rem !important;
}
.pb-8,
.py-8
{
padding-bottom: 8rem !important;
}
.pl-8,
.px-8
{
padding-left: 8rem !important;
}
.p-9
{
padding: 10rem !important;
}
.pt-9,
.py-9
{
padding-top: 10rem !important;
}
.pr-9,
.px-9
{
padding-right: 10rem !important;
}
.pb-9,
.py-9
{
padding-bottom: 10rem !important;
}
.pl-9,
.px-9
{
padding-left: 10rem !important;
}
.m-auto
{
margin: auto !important;
}
.mt-auto,
.my-auto
{
margin-top: auto !important;
}
.mr-auto,
.mx-auto
{
margin-right: auto !important;
}
.mb-auto,
.my-auto
{
margin-bottom: auto !important;
}
.ml-auto,
.mx-auto
{
margin-left: auto !important;
}
@media (min-width: 576px)
{
.m-sm-0
{
margin: 0 !important;
}
.mt-sm-0,
.my-sm-0
{
margin-top: 0 !important;
}
.mr-sm-0,
.mx-sm-0
{
margin-right: 0 !important;
}
.mb-sm-0,
.my-sm-0
{
margin-bottom: 0 !important;
}
.ml-sm-0,
.mx-sm-0
{
margin-left: 0 !important;
}
.m-sm-1
{
margin: .25rem !important;
}
.mt-sm-1,
.my-sm-1
{
margin-top: .25rem !important;
}
.mr-sm-1,
.mx-sm-1
{
margin-right: .25rem !important;
}
.mb-sm-1,
.my-sm-1
{
margin-bottom: .25rem !important;
}
.ml-sm-1,
.mx-sm-1
{
margin-left: .25rem !important;
}
.m-sm-2
{
margin: .5rem !important;
}
.mt-sm-2,
.my-sm-2
{
margin-top: .5rem !important;
}
.mr-sm-2,
.mx-sm-2
{
margin-right: .5rem !important;
}
.mb-sm-2,
.my-sm-2
{
margin-bottom: .5rem !important;
}
.ml-sm-2,
.mx-sm-2
{
margin-left: .5rem !important;
}
.m-sm-3
{
margin: 1rem !important;
}
.mt-sm-3,
.my-sm-3
{
margin-top: 1rem !important;
}
.mr-sm-3,
.mx-sm-3
{
margin-right: 1rem !important;
}
.mb-sm-3,
.my-sm-3
{
margin-bottom: 1rem !important;
}
.ml-sm-3,
.mx-sm-3
{
margin-left: 1rem !important;
}
.m-sm-4
{
margin: 1.5rem !important;
}
.mt-sm-4,
.my-sm-4
{
margin-top: 1.5rem !important;
}
.mr-sm-4,
.mx-sm-4
{
margin-right: 1.5rem !important;
}
.mb-sm-4,
.my-sm-4
{
margin-bottom: 1.5rem !important;
}
.ml-sm-4,
.mx-sm-4
{
margin-left: 1.5rem !important;
}
.m-sm-5
{
margin: 3rem !important;
}
.mt-sm-5,
.my-sm-5
{
margin-top: 3rem !important;
}
.mr-sm-5,
.mx-sm-5
{
margin-right: 3rem !important;
}
.mb-sm-5,
.my-sm-5
{
margin-bottom: 3rem !important;
}
.ml-sm-5,
.mx-sm-5
{
margin-left: 3rem !important;
}
.m-sm--9
{
margin: -10rem !important;
}
.mt-sm--9,
.my-sm--9
{
margin-top: -10rem !important;
}
.mr-sm--9,
.mx-sm--9
{
margin-right: -10rem !important;
}
.mb-sm--9,
.my-sm--9
{
margin-bottom: -10rem !important;
}
.ml-sm--9,
.mx-sm--9
{
margin-left: -10rem !important;
}
.m-sm--8
{
margin: -8rem !important;
}
.mt-sm--8,
.my-sm--8
{
margin-top: -8rem !important;
}
.mr-sm--8,
.mx-sm--8
{
margin-right: -8rem !important;
}
.mb-sm--8,
.my-sm--8
{
margin-bottom: -8rem !important;
}
.ml-sm--8,
.mx-sm--8
{
margin-left: -8rem !important;
}
.m-sm--7
{
margin: -6rem !important;
}
.mt-sm--7,
.my-sm--7
{
margin-top: -6rem !important;
}
.mr-sm--7,
.mx-sm--7
{
margin-right: -6rem !important;
}
.mb-sm--7,
.my-sm--7
{
margin-bottom: -6rem !important;
}
.ml-sm--7,
.mx-sm--7
{
margin-left: -6rem !important;
}
.m-sm--6
{
margin: -4.5rem !important;
}
.mt-sm--6,
.my-sm--6
{
margin-top: -4.5rem !important;
}
.mr-sm--6,
.mx-sm--6
{
margin-right: -4.5rem !important;
}
.mb-sm--6,
.my-sm--6
{
margin-bottom: -4.5rem !important;
}
.ml-sm--6,
.mx-sm--6
{
margin-left: -4.5rem !important;
}
.m-sm--5
{
margin: -3rem !important;
}
.mt-sm--5,
.my-sm--5
{
margin-top: -3rem !important;
}
.mr-sm--5,
.mx-sm--5
{
margin-right: -3rem !important;
}
.mb-sm--5,
.my-sm--5
{
margin-bottom: -3rem !important;
}
.ml-sm--5,
.mx-sm--5
{
margin-left: -3rem !important;
}
.m-sm--4
{
margin: -1.5rem !important;
}
.mt-sm--4,
.my-sm--4
{
margin-top: -1.5rem !important;
}
.mr-sm--4,
.mx-sm--4
{
margin-right: -1.5rem !important;
}
.mb-sm--4,
.my-sm--4
{
margin-bottom: -1.5rem !important;
}
.ml-sm--4,
.mx-sm--4
{
margin-left: -1.5rem !important;
}
.m-sm--3
{
margin: -1rem !important;
}
.mt-sm--3,
.my-sm--3
{
margin-top: -1rem !important;
}
.mr-sm--3,
.mx-sm--3
{
margin-right: -1rem !important;
}
.mb-sm--3,
.my-sm--3
{
margin-bottom: -1rem !important;
}
.ml-sm--3,
.mx-sm--3
{
margin-left: -1rem !important;
}
.m-sm--2
{
margin: -.5rem !important;
}
.mt-sm--2,
.my-sm--2
{
margin-top: -.5rem !important;
}
.mr-sm--2,
.mx-sm--2
{
margin-right: -.5rem !important;
}
.mb-sm--2,
.my-sm--2
{
margin-bottom: -.5rem !important;
}
.ml-sm--2,
.mx-sm--2
{
margin-left: -.5rem !important;
}
.m-sm--1
{
margin: -.25rem !important;
}
.mt-sm--1,
.my-sm--1
{
margin-top: -.25rem !important;
}
.mr-sm--1,
.mx-sm--1
{
margin-right: -.25rem !important;
}
.mb-sm--1,
.my-sm--1
{
margin-bottom: -.25rem !important;
}
.ml-sm--1,
.mx-sm--1
{
margin-left: -.25rem !important;
}
.m-sm-6
{
margin: 4.5rem !important;
}
.mt-sm-6,
.my-sm-6
{
margin-top: 4.5rem !important;
}
.mr-sm-6,
.mx-sm-6
{
margin-right: 4.5rem !important;
}
.mb-sm-6,
.my-sm-6
{
margin-bottom: 4.5rem !important;
}
.ml-sm-6,
.mx-sm-6
{
margin-left: 4.5rem !important;
}
.m-sm-7
{
margin: 6rem !important;
}
.mt-sm-7,
.my-sm-7
{
margin-top: 6rem !important;
}
.mr-sm-7,
.mx-sm-7
{
margin-right: 6rem !important;
}
.mb-sm-7,
.my-sm-7
{
margin-bottom: 6rem !important;
}
.ml-sm-7,
.mx-sm-7
{
margin-left: 6rem !important;
}
.m-sm-8
{
margin: 8rem !important;
}
.mt-sm-8,
.my-sm-8
{
margin-top: 8rem !important;
}
.mr-sm-8,
.mx-sm-8
{
margin-right: 8rem !important;
}
.mb-sm-8,
.my-sm-8
{
margin-bottom: 8rem !important;
}
.ml-sm-8,
.mx-sm-8
{
margin-left: 8rem !important;
}
.m-sm-9
{
margin: 10rem !important;
}
.mt-sm-9,
.my-sm-9
{
margin-top: 10rem !important;
}
.mr-sm-9,
.mx-sm-9
{
margin-right: 10rem !important;
}
.mb-sm-9,
.my-sm-9
{
margin-bottom: 10rem !important;
}
.ml-sm-9,
.mx-sm-9
{
margin-left: 10rem !important;
}
.p-sm-0
{
padding: 0 !important;
}
.pt-sm-0,
.py-sm-0
{
padding-top: 0 !important;
}
.pr-sm-0,
.px-sm-0
{
padding-right: 0 !important;
}
.pb-sm-0,
.py-sm-0
{
padding-bottom: 0 !important;
}
.pl-sm-0,
.px-sm-0
{
padding-left: 0 !important;
}
.p-sm-1
{
padding: .25rem !important;
}
.pt-sm-1,
.py-sm-1
{
padding-top: .25rem !important;
}
.pr-sm-1,
.px-sm-1
{
padding-right: .25rem !important;
}
.pb-sm-1,
.py-sm-1
{
padding-bottom: .25rem !important;
}
.pl-sm-1,
.px-sm-1
{
padding-left: .25rem !important;
}
.p-sm-2
{
padding: .5rem !important;
}
.pt-sm-2,
.py-sm-2
{
padding-top: .5rem !important;
}
.pr-sm-2,
.px-sm-2
{
padding-right: .5rem !important;
}
.pb-sm-2,
.py-sm-2
{
padding-bottom: .5rem !important;
}
.pl-sm-2,
.px-sm-2
{
padding-left: .5rem !important;
}
.p-sm-3
{
padding: 1rem !important;
}
.pt-sm-3,
.py-sm-3
{
padding-top: 1rem !important;
}
.pr-sm-3,
.px-sm-3
{
padding-right: 1rem !important;
}
.pb-sm-3,
.py-sm-3
{
padding-bottom: 1rem !important;
}
.pl-sm-3,
.px-sm-3
{
padding-left: 1rem !important;
}
.p-sm-4
{
padding: 1.5rem !important;
}
.pt-sm-4,
.py-sm-4
{
padding-top: 1.5rem !important;
}
.pr-sm-4,
.px-sm-4
{
padding-right: 1.5rem !important;
}
.pb-sm-4,
.py-sm-4
{
padding-bottom: 1.5rem !important;
}
.pl-sm-4,
.px-sm-4
{
padding-left: 1.5rem !important;
}
.p-sm-5
{
padding: 3rem !important;
}
.pt-sm-5,
.py-sm-5
{
padding-top: 3rem !important;
}
.pr-sm-5,
.px-sm-5
{
padding-right: 3rem !important;
}
.pb-sm-5,
.py-sm-5
{
padding-bottom: 3rem !important;
}
.pl-sm-5,
.px-sm-5
{
padding-left: 3rem !important;
}
.p-sm--9
{
padding: -10rem !important;
}
.pt-sm--9,
.py-sm--9
{
padding-top: -10rem !important;
}
.pr-sm--9,
.px-sm--9
{
padding-right: -10rem !important;
}
.pb-sm--9,
.py-sm--9
{
padding-bottom: -10rem !important;
}
.pl-sm--9,
.px-sm--9
{
padding-left: -10rem !important;
}
.p-sm--8
{
padding: -8rem !important;
}
.pt-sm--8,
.py-sm--8
{
padding-top: -8rem !important;
}
.pr-sm--8,
.px-sm--8
{
padding-right: -8rem !important;
}
.pb-sm--8,
.py-sm--8
{
padding-bottom: -8rem !important;
}
.pl-sm--8,
.px-sm--8
{
padding-left: -8rem !important;
}
.p-sm--7
{
padding: -6rem !important;
}
.pt-sm--7,
.py-sm--7
{
padding-top: -6rem !important;
}
.pr-sm--7,
.px-sm--7
{
padding-right: -6rem !important;
}
.pb-sm--7,
.py-sm--7
{
padding-bottom: -6rem !important;
}
.pl-sm--7,
.px-sm--7
{
padding-left: -6rem !important;
}
.p-sm--6
{
padding: -4.5rem !important;
}
.pt-sm--6,
.py-sm--6
{
padding-top: -4.5rem !important;
}
.pr-sm--6,
.px-sm--6
{
padding-right: -4.5rem !important;
}
.pb-sm--6,
.py-sm--6
{
padding-bottom: -4.5rem !important;
}
.pl-sm--6,
.px-sm--6
{
padding-left: -4.5rem !important;
}
.p-sm--5
{
padding: -3rem !important;
}
.pt-sm--5,
.py-sm--5
{
padding-top: -3rem !important;
}
.pr-sm--5,
.px-sm--5
{
padding-right: -3rem !important;
}
.pb-sm--5,
.py-sm--5
{
padding-bottom: -3rem !important;
}
.pl-sm--5,
.px-sm--5
{
padding-left: -3rem !important;
}
.p-sm--4
{
padding: -1.5rem !important;
}
.pt-sm--4,
.py-sm--4
{
padding-top: -1.5rem !important;
}
.pr-sm--4,
.px-sm--4
{
padding-right: -1.5rem !important;
}
.pb-sm--4,
.py-sm--4
{
padding-bottom: -1.5rem !important;
}
.pl-sm--4,
.px-sm--4
{
padding-left: -1.5rem !important;
}
.p-sm--3
{
padding: -1rem !important;
}
.pt-sm--3,
.py-sm--3
{
padding-top: -1rem !important;
}
.pr-sm--3,
.px-sm--3
{
padding-right: -1rem !important;
}
.pb-sm--3,
.py-sm--3
{
padding-bottom: -1rem !important;
}
.pl-sm--3,
.px-sm--3
{
padding-left: -1rem !important;
}
.p-sm--2
{
padding: -.5rem !important;
}
.pt-sm--2,
.py-sm--2
{
padding-top: -.5rem !important;
}
.pr-sm--2,
.px-sm--2
{
padding-right: -.5rem !important;
}
.pb-sm--2,
.py-sm--2
{
padding-bottom: -.5rem !important;
}
.pl-sm--2,
.px-sm--2
{
padding-left: -.5rem !important;
}
.p-sm--1
{
padding: -.25rem !important;
}
.pt-sm--1,
.py-sm--1
{
padding-top: -.25rem !important;
}
.pr-sm--1,
.px-sm--1
{
padding-right: -.25rem !important;
}
.pb-sm--1,
.py-sm--1
{
padding-bottom: -.25rem !important;
}
.pl-sm--1,
.px-sm--1
{
padding-left: -.25rem !important;
}
.p-sm-6
{
padding: 4.5rem !important;
}
.pt-sm-6,
.py-sm-6
{
padding-top: 4.5rem !important;
}
.pr-sm-6,
.px-sm-6
{
padding-right: 4.5rem !important;
}
.pb-sm-6,
.py-sm-6
{
padding-bottom: 4.5rem !important;
}
.pl-sm-6,
.px-sm-6
{
padding-left: 4.5rem !important;
}
.p-sm-7
{
padding: 6rem !important;
}
.pt-sm-7,
.py-sm-7
{
padding-top: 6rem !important;
}
.pr-sm-7,
.px-sm-7
{
padding-right: 6rem !important;
}
.pb-sm-7,
.py-sm-7
{
padding-bottom: 6rem !important;
}
.pl-sm-7,
.px-sm-7
{
padding-left: 6rem !important;
}
.p-sm-8
{
padding: 8rem !important;
}
.pt-sm-8,
.py-sm-8
{
padding-top: 8rem !important;
}
.pr-sm-8,
.px-sm-8
{
padding-right: 8rem !important;
}
.pb-sm-8,
.py-sm-8
{
padding-bottom: 8rem !important;
}
.pl-sm-8,
.px-sm-8
{
padding-left: 8rem !important;
}
.p-sm-9
{
padding: 10rem !important;
}
.pt-sm-9,
.py-sm-9
{
padding-top: 10rem !important;
}
.pr-sm-9,
.px-sm-9
{
padding-right: 10rem !important;
}
.pb-sm-9,
.py-sm-9
{
padding-bottom: 10rem !important;
}
.pl-sm-9,
.px-sm-9
{
padding-left: 10rem !important;
}
.m-sm-auto
{
margin: auto !important;
}
.mt-sm-auto,
.my-sm-auto
{
margin-top: auto !important;
}
.mr-sm-auto,
.mx-sm-auto
{
margin-right: auto !important;
}
.mb-sm-auto,
.my-sm-auto
{
margin-bottom: auto !important;
}
.ml-sm-auto,
.mx-sm-auto
{
margin-left: auto !important;
}
}
@media (min-width: 768px)
{
.m-md-0
{
margin: 0 !important;
}
.mt-md-0,
.my-md-0
{
margin-top: 0 !important;
}
.mr-md-0,
.mx-md-0
{
margin-right: 0 !important;
}
.mb-md-0,
.my-md-0
{
margin-bottom: 0 !important;
}
.ml-md-0,
.mx-md-0
{
margin-left: 0 !important;
}
.m-md-1
{
margin: .25rem !important;
}
.mt-md-1,
.my-md-1
{
margin-top: .25rem !important;
}
.mr-md-1,
.mx-md-1
{
margin-right: .25rem !important;
}
.mb-md-1,
.my-md-1
{
margin-bottom: .25rem !important;
}
.ml-md-1,
.mx-md-1
{
margin-left: .25rem !important;
}
.m-md-2
{
margin: .5rem !important;
}
.mt-md-2,
.my-md-2
{
margin-top: .5rem !important;
}
.mr-md-2,
.mx-md-2
{
margin-right: .5rem !important;
}
.mb-md-2,
.my-md-2
{
margin-bottom: .5rem !important;
}
.ml-md-2,
.mx-md-2
{
margin-left: .5rem !important;
}
.m-md-3
{
margin: 1rem !important;
}
.mt-md-3,
.my-md-3
{
margin-top: 1rem !important;
}
.mr-md-3,
.mx-md-3
{
margin-right: 1rem !important;
}
.mb-md-3,
.my-md-3
{
margin-bottom: 1rem !important;
}
.ml-md-3,
.mx-md-3
{
margin-left: 1rem !important;
}
.m-md-4
{
margin: 1.5rem !important;
}
.mt-md-4,
.my-md-4
{
margin-top: 1.5rem !important;
}
.mr-md-4,
.mx-md-4
{
margin-right: 1.5rem !important;
}
.mb-md-4,
.my-md-4
{
margin-bottom: 1.5rem !important;
}
.ml-md-4,
.mx-md-4
{
margin-left: 1.5rem !important;
}
.m-md-5
{
margin: 3rem !important;
}
.mt-md-5,
.my-md-5
{
margin-top: 3rem !important;
}
.mr-md-5,
.mx-md-5
{
margin-right: 3rem !important;
}
.mb-md-5,
.my-md-5
{
margin-bottom: 3rem !important;
}
.ml-md-5,
.mx-md-5
{
margin-left: 3rem !important;
}
.m-md--9
{
margin: -10rem !important;
}
.mt-md--9,
.my-md--9
{
margin-top: -10rem !important;
}
.mr-md--9,
.mx-md--9
{
margin-right: -10rem !important;
}
.mb-md--9,
.my-md--9
{
margin-bottom: -10rem !important;
}
.ml-md--9,
.mx-md--9
{
margin-left: -10rem !important;
}
.m-md--8
{
margin: -8rem !important;
}
.mt-md--8,
.my-md--8
{
margin-top: -8rem !important;
}
.mr-md--8,
.mx-md--8
{
margin-right: -8rem !important;
}
.mb-md--8,
.my-md--8
{
margin-bottom: -8rem !important;
}
.ml-md--8,
.mx-md--8
{
margin-left: -8rem !important;
}
.m-md--7
{
margin: -6rem !important;
}
.mt-md--7,
.my-md--7
{
margin-top: -6rem !important;
}
.mr-md--7,
.mx-md--7
{
margin-right: -6rem !important;
}
.mb-md--7,
.my-md--7
{
margin-bottom: -6rem !important;
}
.ml-md--7,
.mx-md--7
{
margin-left: -6rem !important;
}
.m-md--6
{
margin: -4.5rem !important;
}
.mt-md--6,
.my-md--6
{
margin-top: -4.5rem !important;
}
.mr-md--6,
.mx-md--6
{
margin-right: -4.5rem !important;
}
.mb-md--6,
.my-md--6
{
margin-bottom: -4.5rem !important;
}
.ml-md--6,
.mx-md--6
{
margin-left: -4.5rem !important;
}
.m-md--5
{
margin: -3rem !important;
}
.mt-md--5,
.my-md--5
{
margin-top: -3rem !important;
}
.mr-md--5,
.mx-md--5
{
margin-right: -3rem !important;
}
.mb-md--5,
.my-md--5
{
margin-bottom: -3rem !important;
}
.ml-md--5,
.mx-md--5
{
margin-left: -3rem !important;
}
.m-md--4
{
margin: -1.5rem !important;
}
.mt-md--4,
.my-md--4
{
margin-top: -1.5rem !important;
}
.mr-md--4,
.mx-md--4
{
margin-right: -1.5rem !important;
}
.mb-md--4,
.my-md--4
{
margin-bottom: -1.5rem !important;
}
.ml-md--4,
.mx-md--4
{
margin-left: -1.5rem !important;
}
.m-md--3
{
margin: -1rem !important;
}
.mt-md--3,
.my-md--3
{
margin-top: -1rem !important;
}
.mr-md--3,
.mx-md--3
{
margin-right: -1rem !important;
}
.mb-md--3,
.my-md--3
{
margin-bottom: -1rem !important;
}
.ml-md--3,
.mx-md--3
{
margin-left: -1rem !important;
}
.m-md--2
{
margin: -.5rem !important;
}
.mt-md--2,
.my-md--2
{
margin-top: -.5rem !important;
}
.mr-md--2,
.mx-md--2
{
margin-right: -.5rem !important;
}
.mb-md--2,
.my-md--2
{
margin-bottom: -.5rem !important;
}
.ml-md--2,
.mx-md--2
{
margin-left: -.5rem !important;
}
.m-md--1
{
margin: -.25rem !important;
}
.mt-md--1,
.my-md--1
{
margin-top: -.25rem !important;
}
.mr-md--1,
.mx-md--1
{
margin-right: -.25rem !important;
}
.mb-md--1,
.my-md--1
{
margin-bottom: -.25rem !important;
}
.ml-md--1,
.mx-md--1
{
margin-left: -.25rem !important;
}
.m-md-6
{
margin: 4.5rem !important;
}
.mt-md-6,
.my-md-6
{
margin-top: 4.5rem !important;
}
.mr-md-6,
.mx-md-6
{
margin-right: 4.5rem !important;
}
.mb-md-6,
.my-md-6
{
margin-bottom: 4.5rem !important;
}
.ml-md-6,
.mx-md-6
{
margin-left: 4.5rem !important;
}
.m-md-7
{
margin: 6rem !important;
}
.mt-md-7,
.my-md-7
{
margin-top: 6rem !important;
}
.mr-md-7,
.mx-md-7
{
margin-right: 6rem !important;
}
.mb-md-7,
.my-md-7
{
margin-bottom: 6rem !important;
}
.ml-md-7,
.mx-md-7
{
margin-left: 6rem !important;
}
.m-md-8
{
margin: 8rem !important;
}
.mt-md-8,
.my-md-8
{
margin-top: 8rem !important;
}
.mr-md-8,
.mx-md-8
{
margin-right: 8rem !important;
}
.mb-md-8,
.my-md-8
{
margin-bottom: 8rem !important;
}
.ml-md-8,
.mx-md-8
{
margin-left: 8rem !important;
}
.m-md-9
{
margin: 10rem !important;
}
.mt-md-9,
.my-md-9
{
margin-top: 10rem !important;
}
.mr-md-9,
.mx-md-9
{
margin-right: 10rem !important;
}
.mb-md-9,
.my-md-9
{
margin-bottom: 10rem !important;
}
.ml-md-9,
.mx-md-9
{
margin-left: 10rem !important;
}
.p-md-0
{
padding: 0 !important;
}
.pt-md-0,
.py-md-0
{
padding-top: 0 !important;
}
.pr-md-0,
.px-md-0
{
padding-right: 0 !important;
}
.pb-md-0,
.py-md-0
{
padding-bottom: 0 !important;
}
.pl-md-0,
.px-md-0
{
padding-left: 0 !important;
}
.p-md-1
{
padding: .25rem !important;
}
.pt-md-1,
.py-md-1
{
padding-top: .25rem !important;
}
.pr-md-1,
.px-md-1
{
padding-right: .25rem !important;
}
.pb-md-1,
.py-md-1
{
padding-bottom: .25rem !important;
}
.pl-md-1,
.px-md-1
{
padding-left: .25rem !important;
}
.p-md-2
{
padding: .5rem !important;
}
.pt-md-2,
.py-md-2
{
padding-top: .5rem !important;
}
.pr-md-2,
.px-md-2
{
padding-right: .5rem !important;
}
.pb-md-2,
.py-md-2
{
padding-bottom: .5rem !important;
}
.pl-md-2,
.px-md-2
{
padding-left: .5rem !important;
}
.p-md-3
{
padding: 1rem !important;
}
.pt-md-3,
.py-md-3
{
padding-top: 1rem !important;
}
.pr-md-3,
.px-md-3
{
padding-right: 1rem !important;
}
.pb-md-3,
.py-md-3
{
padding-bottom: 1rem !important;
}
.pl-md-3,
.px-md-3
{
padding-left: 1rem !important;
}
.p-md-4
{
padding: 1.5rem !important;
}
.pt-md-4,
.py-md-4
{
padding-top: 1.5rem !important;
}
.pr-md-4,
.px-md-4
{
padding-right: 1.5rem !important;
}
.pb-md-4,
.py-md-4
{
padding-bottom: 1.5rem !important;
}
.pl-md-4,
.px-md-4
{
padding-left: 1.5rem !important;
}
.p-md-5
{
padding: 3rem !important;
}
.pt-md-5,
.py-md-5
{
padding-top: 3rem !important;
}
.pr-md-5,
.px-md-5
{
padding-right: 3rem !important;
}
.pb-md-5,
.py-md-5
{
padding-bottom: 3rem !important;
}
.pl-md-5,
.px-md-5
{
padding-left: 3rem !important;
}
.p-md--9
{
padding: -10rem !important;
}
.pt-md--9,
.py-md--9
{
padding-top: -10rem !important;
}
.pr-md--9,
.px-md--9
{
padding-right: -10rem !important;
}
.pb-md--9,
.py-md--9
{
padding-bottom: -10rem !important;
}
.pl-md--9,
.px-md--9
{
padding-left: -10rem !important;
}
.p-md--8
{
padding: -8rem !important;
}
.pt-md--8,
.py-md--8
{
padding-top: -8rem !important;
}
.pr-md--8,
.px-md--8
{
padding-right: -8rem !important;
}
.pb-md--8,
.py-md--8
{
padding-bottom: -8rem !important;
}
.pl-md--8,
.px-md--8
{
padding-left: -8rem !important;
}
.p-md--7
{
padding: -6rem !important;
}
.pt-md--7,
.py-md--7
{
padding-top: -6rem !important;
}
.pr-md--7,
.px-md--7
{
padding-right: -6rem !important;
}
.pb-md--7,
.py-md--7
{
padding-bottom: -6rem !important;
}
.pl-md--7,
.px-md--7
{
padding-left: -6rem !important;
}
.p-md--6
{
padding: -4.5rem !important;
}
.pt-md--6,
.py-md--6
{
padding-top: -4.5rem !important;
}
.pr-md--6,
.px-md--6
{
padding-right: -4.5rem !important;
}
.pb-md--6,
.py-md--6
{
padding-bottom: -4.5rem !important;
}
.pl-md--6,
.px-md--6
{
padding-left: -4.5rem !important;
}
.p-md--5
{
padding: -3rem !important;
}
.pt-md--5,
.py-md--5
{
padding-top: -3rem !important;
}
.pr-md--5,
.px-md--5
{
padding-right: -3rem !important;
}
.pb-md--5,
.py-md--5
{
padding-bottom: -3rem !important;
}
.pl-md--5,
.px-md--5
{
padding-left: -3rem !important;
}
.p-md--4
{
padding: -1.5rem !important;
}
.pt-md--4,
.py-md--4
{
padding-top: -1.5rem !important;
}
.pr-md--4,
.px-md--4
{
padding-right: -1.5rem !important;
}
.pb-md--4,
.py-md--4
{
padding-bottom: -1.5rem !important;
}
.pl-md--4,
.px-md--4
{
padding-left: -1.5rem !important;
}
.p-md--3
{
padding: -1rem !important;
}
.pt-md--3,
.py-md--3
{
padding-top: -1rem !important;
}
.pr-md--3,
.px-md--3
{
padding-right: -1rem !important;
}
.pb-md--3,
.py-md--3
{
padding-bottom: -1rem !important;
}
.pl-md--3,
.px-md--3
{
padding-left: -1rem !important;
}
.p-md--2
{
padding: -.5rem !important;
}
.pt-md--2,
.py-md--2
{
padding-top: -.5rem !important;
}
.pr-md--2,
.px-md--2
{
padding-right: -.5rem !important;
}
.pb-md--2,
.py-md--2
{
padding-bottom: -.5rem !important;
}
.pl-md--2,
.px-md--2
{
padding-left: -.5rem !important;
}
.p-md--1
{
padding: -.25rem !important;
}
.pt-md--1,
.py-md--1
{
padding-top: -.25rem !important;
}
.pr-md--1,
.px-md--1
{
padding-right: -.25rem !important;
}
.pb-md--1,
.py-md--1
{
padding-bottom: -.25rem !important;
}
.pl-md--1,
.px-md--1
{
padding-left: -.25rem !important;
}
.p-md-6
{
padding: 4.5rem !important;
}
.pt-md-6,
.py-md-6
{
padding-top: 4.5rem !important;
}
.pr-md-6,
.px-md-6
{
padding-right: 4.5rem !important;
}
.pb-md-6,
.py-md-6
{
padding-bottom: 4.5rem !important;
}
.pl-md-6,
.px-md-6
{
padding-left: 4.5rem !important;
}
.p-md-7
{
padding: 6rem !important;
}
.pt-md-7,
.py-md-7
{
padding-top: 6rem !important;
}
.pr-md-7,
.px-md-7
{
padding-right: 6rem !important;
}
.pb-md-7,
.py-md-7
{
padding-bottom: 6rem !important;
}
.pl-md-7,
.px-md-7
{
padding-left: 6rem !important;
}
.p-md-8
{
padding: 8rem !important;
}
.pt-md-8,
.py-md-8
{
padding-top: 8rem !important;
}
.pr-md-8,
.px-md-8
{
padding-right: 8rem !important;
}
.pb-md-8,
.py-md-8
{
padding-bottom: 8rem !important;
}
.pl-md-8,
.px-md-8
{
padding-left: 8rem !important;
}
.p-md-9
{
padding: 10rem !important;
}
.pt-md-9,
.py-md-9
{
padding-top: 10rem !important;
}
.pr-md-9,
.px-md-9
{
padding-right: 10rem !important;
}
.pb-md-9,
.py-md-9
{
padding-bottom: 10rem !important;
}
.pl-md-9,
.px-md-9
{
padding-left: 10rem !important;
}
.m-md-auto
{
margin: auto !important;
}
.mt-md-auto,
.my-md-auto
{
margin-top: auto !important;
}
.mr-md-auto,
.mx-md-auto
{
margin-right: auto !important;
}
.mb-md-auto,
.my-md-auto
{
margin-bottom: auto !important;
}
.ml-md-auto,
.mx-md-auto
{
margin-left: auto !important;
}
}
@media (min-width: 992px)
{
.m-lg-0
{
margin: 0 !important;
}
.mt-lg-0,
.my-lg-0
{
margin-top: 0 !important;
}
.mr-lg-0,
.mx-lg-0
{
margin-right: 0 !important;
}
.mb-lg-0,
.my-lg-0
{
margin-bottom: 0 !important;
}
.ml-lg-0,
.mx-lg-0
{
margin-left: 0 !important;
}
.m-lg-1
{
margin: .25rem !important;
}
.mt-lg-1,
.my-lg-1
{
margin-top: .25rem !important;
}
.mr-lg-1,
.mx-lg-1
{
margin-right: .25rem !important;
}
.mb-lg-1,
.my-lg-1
{
margin-bottom: .25rem !important;
}
.ml-lg-1,
.mx-lg-1
{
margin-left: .25rem !important;
}
.m-lg-2
{
margin: .5rem !important;
}
.mt-lg-2,
.my-lg-2
{
margin-top: .5rem !important;
}
.mr-lg-2,
.mx-lg-2
{
margin-right: .5rem !important;
}
.mb-lg-2,
.my-lg-2
{
margin-bottom: .5rem !important;
}
.ml-lg-2,
.mx-lg-2
{
margin-left: .5rem !important;
}
.m-lg-3
{
margin: 1rem !important;
}
.mt-lg-3,
.my-lg-3
{
margin-top: 1rem !important;
}
.mr-lg-3,
.mx-lg-3
{
margin-right: 1rem !important;
}
.mb-lg-3,
.my-lg-3
{
margin-bottom: 1rem !important;
}
.ml-lg-3,
.mx-lg-3
{
margin-left: 1rem !important;
}
.m-lg-4
{
margin: 1.5rem !important;
}
.mt-lg-4,
.my-lg-4
{
margin-top: 1.5rem !important;
}
.mr-lg-4,
.mx-lg-4
{
margin-right: 1.5rem !important;
}
.mb-lg-4,
.my-lg-4
{
margin-bottom: 1.5rem !important;
}
.ml-lg-4,
.mx-lg-4
{
margin-left: 1.5rem !important;
}
.m-lg-5
{
margin: 3rem !important;
}
.mt-lg-5,
.my-lg-5
{
margin-top: 3rem !important;
}
.mr-lg-5,
.mx-lg-5
{
margin-right: 3rem !important;
}
.mb-lg-5,
.my-lg-5
{
margin-bottom: 3rem !important;
}
.ml-lg-5,
.mx-lg-5
{
margin-left: 3rem !important;
}
.m-lg--9
{
margin: -10rem !important;
}
.mt-lg--9,
.my-lg--9
{
margin-top: -10rem !important;
}
.mr-lg--9,
.mx-lg--9
{
margin-right: -10rem !important;
}
.mb-lg--9,
.my-lg--9
{
margin-bottom: -10rem !important;
}
.ml-lg--9,
.mx-lg--9
{
margin-left: -10rem !important;
}
.m-lg--8
{
margin: -8rem !important;
}
.mt-lg--8,
.my-lg--8
{
margin-top: -8rem !important;
}
.mr-lg--8,
.mx-lg--8
{
margin-right: -8rem !important;
}
.mb-lg--8,
.my-lg--8
{
margin-bottom: -8rem !important;
}
.ml-lg--8,
.mx-lg--8
{
margin-left: -8rem !important;
}
.m-lg--7
{
margin: -6rem !important;
}
.mt-lg--7,
.my-lg--7
{
margin-top: -6rem !important;
}
.mr-lg--7,
.mx-lg--7
{
margin-right: -6rem !important;
}
.mb-lg--7,
.my-lg--7
{
margin-bottom: -6rem !important;
}
.ml-lg--7,
.mx-lg--7
{
margin-left: -6rem !important;
}
.m-lg--6
{
margin: -4.5rem !important;
}
.mt-lg--6,
.my-lg--6
{
margin-top: -4.5rem !important;
}
.mr-lg--6,
.mx-lg--6
{
margin-right: -4.5rem !important;
}
.mb-lg--6,
.my-lg--6
{
margin-bottom: -4.5rem !important;
}
.ml-lg--6,
.mx-lg--6
{
margin-left: -4.5rem !important;
}
.m-lg--5
{
margin: -3rem !important;
}
.mt-lg--5,
.my-lg--5
{
margin-top: -3rem !important;
}
.mr-lg--5,
.mx-lg--5
{
margin-right: -3rem !important;
}
.mb-lg--5,
.my-lg--5
{
margin-bottom: -3rem !important;
}
.ml-lg--5,
.mx-lg--5
{
margin-left: -3rem !important;
}
.m-lg--4
{
margin: -1.5rem !important;
}
.mt-lg--4,
.my-lg--4
{
margin-top: -1.5rem !important;
}
.mr-lg--4,
.mx-lg--4
{
margin-right: -1.5rem !important;
}
.mb-lg--4,
.my-lg--4
{
margin-bottom: -1.5rem !important;
}
.ml-lg--4,
.mx-lg--4
{
margin-left: -1.5rem !important;
}
.m-lg--3
{
margin: -1rem !important;
}
.mt-lg--3,
.my-lg--3
{
margin-top: -1rem !important;
}
.mr-lg--3,
.mx-lg--3
{
margin-right: -1rem !important;
}
.mb-lg--3,
.my-lg--3
{
margin-bottom: -1rem !important;
}
.ml-lg--3,
.mx-lg--3
{
margin-left: -1rem !important;
}
.m-lg--2
{
margin: -.5rem !important;
}
.mt-lg--2,
.my-lg--2
{
margin-top: -.5rem !important;
}
.mr-lg--2,
.mx-lg--2
{
margin-right: -.5rem !important;
}
.mb-lg--2,
.my-lg--2
{
margin-bottom: -.5rem !important;
}
.ml-lg--2,
.mx-lg--2
{
margin-left: -.5rem !important;
}
.m-lg--1
{
margin: -.25rem !important;
}
.mt-lg--1,
.my-lg--1
{
margin-top: -.25rem !important;
}
.mr-lg--1,
.mx-lg--1
{
margin-right: -.25rem !important;
}
.mb-lg--1,
.my-lg--1
{
margin-bottom: -.25rem !important;
}
.ml-lg--1,
.mx-lg--1
{
margin-left: -.25rem !important;
}
.m-lg-6
{
margin: 4.5rem !important;
}
.mt-lg-6,
.my-lg-6
{
margin-top: 4.5rem !important;
}
.mr-lg-6,
.mx-lg-6
{
margin-right: 4.5rem !important;
}
.mb-lg-6,
.my-lg-6
{
margin-bottom: 4.5rem !important;
}
.ml-lg-6,
.mx-lg-6
{
margin-left: 4.5rem !important;
}
.m-lg-7
{
margin: 6rem !important;
}
.mt-lg-7,
.my-lg-7
{
margin-top: 6rem !important;
}
.mr-lg-7,
.mx-lg-7
{
margin-right: 6rem !important;
}
.mb-lg-7,
.my-lg-7
{
margin-bottom: 6rem !important;
}
.ml-lg-7,
.mx-lg-7
{
margin-left: 6rem !important;
}
.m-lg-8
{
margin: 8rem !important;
}
.mt-lg-8,
.my-lg-8
{
margin-top: 8rem !important;
}
.mr-lg-8,
.mx-lg-8
{
margin-right: 8rem !important;
}
.mb-lg-8,
.my-lg-8
{
margin-bottom: 8rem !important;
}
.ml-lg-8,
.mx-lg-8
{
margin-left: 8rem !important;
}
.m-lg-9
{
margin: 10rem !important;
}
.mt-lg-9,
.my-lg-9
{
margin-top: 10rem !important;
}
.mr-lg-9,
.mx-lg-9
{
margin-right: 10rem !important;
}
.mb-lg-9,
.my-lg-9
{
margin-bottom: 10rem !important;
}
.ml-lg-9,
.mx-lg-9
{
margin-left: 10rem !important;
}
.p-lg-0
{
padding: 0 !important;
}
.pt-lg-0,
.py-lg-0
{
padding-top: 0 !important;
}
.pr-lg-0,
.px-lg-0
{
padding-right: 0 !important;
}
.pb-lg-0,
.py-lg-0
{
padding-bottom: 0 !important;
}
.pl-lg-0,
.px-lg-0
{
padding-left: 0 !important;
}
.p-lg-1
{
padding: .25rem !important;
}
.pt-lg-1,
.py-lg-1
{
padding-top: .25rem !important;
}
.pr-lg-1,
.px-lg-1
{
padding-right: .25rem !important;
}
.pb-lg-1,
.py-lg-1
{
padding-bottom: .25rem !important;
}
.pl-lg-1,
.px-lg-1
{
padding-left: .25rem !important;
}
.p-lg-2
{
padding: .5rem !important;
}
.pt-lg-2,
.py-lg-2
{
padding-top: .5rem !important;
}
.pr-lg-2,
.px-lg-2
{
padding-right: .5rem !important;
}
.pb-lg-2,
.py-lg-2
{
padding-bottom: .5rem !important;
}
.pl-lg-2,
.px-lg-2
{
padding-left: .5rem !important;
}
.p-lg-3
{
padding: 1rem !important;
}
.pt-lg-3,
.py-lg-3
{
padding-top: 1rem !important;
}
.pr-lg-3,
.px-lg-3
{
padding-right: 1rem !important;
}
.pb-lg-3,
.py-lg-3
{
padding-bottom: 1rem !important;
}
.pl-lg-3,
.px-lg-3
{
padding-left: 1rem !important;
}
.p-lg-4
{
padding: 1.5rem !important;
}
.pt-lg-4,
.py-lg-4
{
padding-top: 1.5rem !important;
}
.pr-lg-4,
.px-lg-4
{
padding-right: 1.5rem !important;
}
.pb-lg-4,
.py-lg-4
{
padding-bottom: 1.5rem !important;
}
.pl-lg-4,
.px-lg-4
{
padding-left: 1.5rem !important;
}
.p-lg-5
{
padding: 3rem !important;
}
.pt-lg-5,
.py-lg-5
{
padding-top: 3rem !important;
}
.pr-lg-5,
.px-lg-5
{
padding-right: 3rem !important;
}
.pb-lg-5,
.py-lg-5
{
padding-bottom: 3rem !important;
}
.pl-lg-5,
.px-lg-5
{
padding-left: 3rem !important;
}
.p-lg--9
{
padding: -10rem !important;
}
.pt-lg--9,
.py-lg--9
{
padding-top: -10rem !important;
}
.pr-lg--9,
.px-lg--9
{
padding-right: -10rem !important;
}
.pb-lg--9,
.py-lg--9
{
padding-bottom: -10rem !important;
}
.pl-lg--9,
.px-lg--9
{
padding-left: -10rem !important;
}
.p-lg--8
{
padding: -8rem !important;
}
.pt-lg--8,
.py-lg--8
{
padding-top: -8rem !important;
}
.pr-lg--8,
.px-lg--8
{
padding-right: -8rem !important;
}
.pb-lg--8,
.py-lg--8
{
padding-bottom: -8rem !important;
}
.pl-lg--8,
.px-lg--8
{
padding-left: -8rem !important;
}
.p-lg--7
{
padding: -6rem !important;
}
.pt-lg--7,
.py-lg--7
{
padding-top: -6rem !important;
}
.pr-lg--7,
.px-lg--7
{
padding-right: -6rem !important;
}
.pb-lg--7,
.py-lg--7
{
padding-bottom: -6rem !important;
}
.pl-lg--7,
.px-lg--7
{
padding-left: -6rem !important;
}
.p-lg--6
{
padding: -4.5rem !important;
}
.pt-lg--6,
.py-lg--6
{
padding-top: -4.5rem !important;
}
.pr-lg--6,
.px-lg--6
{
padding-right: -4.5rem !important;
}
.pb-lg--6,
.py-lg--6
{
padding-bottom: -4.5rem !important;
}
.pl-lg--6,
.px-lg--6
{
padding-left: -4.5rem !important;
}
.p-lg--5
{
padding: -3rem !important;
}
.pt-lg--5,
.py-lg--5
{
padding-top: -3rem !important;
}
.pr-lg--5,
.px-lg--5
{
padding-right: -3rem !important;
}
.pb-lg--5,
.py-lg--5
{
padding-bottom: -3rem !important;
}
.pl-lg--5,
.px-lg--5
{
padding-left: -3rem !important;
}
.p-lg--4
{
padding: -1.5rem !important;
}
.pt-lg--4,
.py-lg--4
{
padding-top: -1.5rem !important;
}
.pr-lg--4,
.px-lg--4
{
padding-right: -1.5rem !important;
}
.pb-lg--4,
.py-lg--4
{
padding-bottom: -1.5rem !important;
}
.pl-lg--4,
.px-lg--4
{
padding-left: -1.5rem !important;
}
.p-lg--3
{
padding: -1rem !important;
}
.pt-lg--3,
.py-lg--3
{
padding-top: -1rem !important;
}
.pr-lg--3,
.px-lg--3
{
padding-right: -1rem !important;
}
.pb-lg--3,
.py-lg--3
{
padding-bottom: -1rem !important;
}
.pl-lg--3,
.px-lg--3
{
padding-left: -1rem !important;
}
.p-lg--2
{
padding: -.5rem !important;
}
.pt-lg--2,
.py-lg--2
{
padding-top: -.5rem !important;
}
.pr-lg--2,
.px-lg--2
{
padding-right: -.5rem !important;
}
.pb-lg--2,
.py-lg--2
{
padding-bottom: -.5rem !important;
}
.pl-lg--2,
.px-lg--2
{
padding-left: -.5rem !important;
}
.p-lg--1
{
padding: -.25rem !important;
}
.pt-lg--1,
.py-lg--1
{
padding-top: -.25rem !important;
}
.pr-lg--1,
.px-lg--1
{
padding-right: -.25rem !important;
}
.pb-lg--1,
.py-lg--1
{
padding-bottom: -.25rem !important;
}
.pl-lg--1,
.px-lg--1
{
padding-left: -.25rem !important;
}
.p-lg-6
{
padding: 4.5rem !important;
}
.pt-lg-6,
.py-lg-6
{
padding-top: 4.5rem !important;
}
.pr-lg-6,
.px-lg-6
{
padding-right: 4.5rem !important;
}
.pb-lg-6,
.py-lg-6
{
padding-bottom: 4.5rem !important;
}
.pl-lg-6,
.px-lg-6
{
padding-left: 4.5rem !important;
}
.p-lg-7
{
padding: 6rem !important;
}
.pt-lg-7,
.py-lg-7
{
padding-top: 6rem !important;
}
.pr-lg-7,
.px-lg-7
{
padding-right: 6rem !important;
}
.pb-lg-7,
.py-lg-7
{
padding-bottom: 6rem !important;
}
.pl-lg-7,
.px-lg-7
{
padding-left: 6rem !important;
}
.p-lg-8
{
padding: 8rem !important;
}
.pt-lg-8,
.py-lg-8
{
padding-top: 8rem !important;
}
.pr-lg-8,
.px-lg-8
{
padding-right: 8rem !important;
}
.pb-lg-8,
.py-lg-8
{
padding-bottom: 8rem !important;
}
.pl-lg-8,
.px-lg-8
{
padding-left: 8rem !important;
}
.p-lg-9
{
padding: 10rem !important;
}
.pt-lg-9,
.py-lg-9
{
padding-top: 10rem !important;
}
.pr-lg-9,
.px-lg-9
{
padding-right: 10rem !important;
}
.pb-lg-9,
.py-lg-9
{
padding-bottom: 10rem !important;
}
.pl-lg-9,
.px-lg-9
{
padding-left: 10rem !important;
}
.m-lg-auto
{
margin: auto !important;
}
.mt-lg-auto,
.my-lg-auto
{
margin-top: auto !important;
}
.mr-lg-auto,
.mx-lg-auto
{
margin-right: auto !important;
}
.mb-lg-auto,
.my-lg-auto
{
margin-bottom: auto !important;
}
.ml-lg-auto,
.mx-lg-auto
{
margin-left: auto !important;
}
}
@media (min-width: 1200px)
{
.m-xl-0
{
margin: 0 !important;
}
.mt-xl-0,
.my-xl-0
{
margin-top: 0 !important;
}
.mr-xl-0,
.mx-xl-0
{
margin-right: 0 !important;
}
.mb-xl-0,
.my-xl-0
{
margin-bottom: 0 !important;
}
.ml-xl-0,
.mx-xl-0
{
margin-left: 0 !important;
}
.m-xl-1
{
margin: .25rem !important;
}
.mt-xl-1,
.my-xl-1
{
margin-top: .25rem !important;
}
.mr-xl-1,
.mx-xl-1
{
margin-right: .25rem !important;
}
.mb-xl-1,
.my-xl-1
{
margin-bottom: .25rem !important;
}
.ml-xl-1,
.mx-xl-1
{
margin-left: .25rem !important;
}
.m-xl-2
{
margin: .5rem !important;
}
.mt-xl-2,
.my-xl-2
{
margin-top: .5rem !important;
}
.mr-xl-2,
.mx-xl-2
{
margin-right: .5rem !important;
}
.mb-xl-2,
.my-xl-2
{
margin-bottom: .5rem !important;
}
.ml-xl-2,
.mx-xl-2
{
margin-left: .5rem !important;
}
.m-xl-3
{
margin: 1rem !important;
}
.mt-xl-3,
.my-xl-3
{
margin-top: 1rem !important;
}
.mr-xl-3,
.mx-xl-3
{
margin-right: 1rem !important;
}
.mb-xl-3,
.my-xl-3
{
margin-bottom: 1rem !important;
}
.ml-xl-3,
.mx-xl-3
{
margin-left: 1rem !important;
}
.m-xl-4
{
margin: 1.5rem !important;
}
.mt-xl-4,
.my-xl-4
{
margin-top: 1.5rem !important;
}
.mr-xl-4,
.mx-xl-4
{
margin-right: 1.5rem !important;
}
.mb-xl-4,
.my-xl-4
{
margin-bottom: 1.5rem !important;
}
.ml-xl-4,
.mx-xl-4
{
margin-left: 1.5rem !important;
}
.m-xl-5
{
margin: 3rem !important;
}
.mt-xl-5,
.my-xl-5
{
margin-top: 3rem !important;
}
.mr-xl-5,
.mx-xl-5
{
margin-right: 3rem !important;
}
.mb-xl-5,
.my-xl-5
{
margin-bottom: 3rem !important;
}
.ml-xl-5,
.mx-xl-5
{
margin-left: 3rem !important;
}
.m-xl--9
{
margin: -10rem !important;
}
.mt-xl--9,
.my-xl--9
{
margin-top: -10rem !important;
}
.mr-xl--9,
.mx-xl--9
{
margin-right: -10rem !important;
}
.mb-xl--9,
.my-xl--9
{
margin-bottom: -10rem !important;
}
.ml-xl--9,
.mx-xl--9
{
margin-left: -10rem !important;
}
.m-xl--8
{
margin: -8rem !important;
}
.mt-xl--8,
.my-xl--8
{
margin-top: -8rem !important;
}
.mr-xl--8,
.mx-xl--8
{
margin-right: -8rem !important;
}
.mb-xl--8,
.my-xl--8
{
margin-bottom: -8rem !important;
}
.ml-xl--8,
.mx-xl--8
{
margin-left: -8rem !important;
}
.m-xl--7
{
margin: -6rem !important;
}
.mt-xl--7,
.my-xl--7
{
margin-top: -6rem !important;
}
.mr-xl--7,
.mx-xl--7
{
margin-right: -6rem !important;
}
.mb-xl--7,
.my-xl--7
{
margin-bottom: -6rem !important;
}
.ml-xl--7,
.mx-xl--7
{
margin-left: -6rem !important;
}
.m-xl--6
{
margin: -4.5rem !important;
}
.mt-xl--6,
.my-xl--6
{
margin-top: -4.5rem !important;
}
.mr-xl--6,
.mx-xl--6
{
margin-right: -4.5rem !important;
}
.mb-xl--6,
.my-xl--6
{
margin-bottom: -4.5rem !important;
}
.ml-xl--6,
.mx-xl--6
{
margin-left: -4.5rem !important;
}
.m-xl--5
{
margin: -3rem !important;
}
.mt-xl--5,
.my-xl--5
{
margin-top: -3rem !important;
}
.mr-xl--5,
.mx-xl--5
{
margin-right: -3rem !important;
}
.mb-xl--5,
.my-xl--5
{
margin-bottom: -3rem !important;
}
.ml-xl--5,
.mx-xl--5
{
margin-left: -3rem !important;
}
.m-xl--4
{
margin: -1.5rem !important;
}
.mt-xl--4,
.my-xl--4
{
margin-top: -1.5rem !important;
}
.mr-xl--4,
.mx-xl--4
{
margin-right: -1.5rem !important;
}
.mb-xl--4,
.my-xl--4
{
margin-bottom: -1.5rem !important;
}
.ml-xl--4,
.mx-xl--4
{
margin-left: -1.5rem !important;
}
.m-xl--3
{
margin: -1rem !important;
}
.mt-xl--3,
.my-xl--3
{
margin-top: -1rem !important;
}
.mr-xl--3,
.mx-xl--3
{
margin-right: -1rem !important;
}
.mb-xl--3,
.my-xl--3
{
margin-bottom: -1rem !important;
}
.ml-xl--3,
.mx-xl--3
{
margin-left: -1rem !important;
}
.m-xl--2
{
margin: -.5rem !important;
}
.mt-xl--2,
.my-xl--2
{
margin-top: -.5rem !important;
}
.mr-xl--2,
.mx-xl--2
{
margin-right: -.5rem !important;
}
.mb-xl--2,
.my-xl--2
{
margin-bottom: -.5rem !important;
}
.ml-xl--2,
.mx-xl--2
{
margin-left: -.5rem !important;
}
.m-xl--1
{
margin: -.25rem !important;
}
.mt-xl--1,
.my-xl--1
{
margin-top: -.25rem !important;
}
.mr-xl--1,
.mx-xl--1
{
margin-right: -.25rem !important;
}
.mb-xl--1,
.my-xl--1
{
margin-bottom: -.25rem !important;
}
.ml-xl--1,
.mx-xl--1
{
margin-left: -.25rem !important;
}
.m-xl-6
{
margin: 4.5rem !important;
}
.mt-xl-6,
.my-xl-6
{
margin-top: 4.5rem !important;
}
.mr-xl-6,
.mx-xl-6
{
margin-right: 4.5rem !important;
}
.mb-xl-6,
.my-xl-6
{
margin-bottom: 4.5rem !important;
}
.ml-xl-6,
.mx-xl-6
{
margin-left: 4.5rem !important;
}
.m-xl-7
{
margin: 6rem !important;
}
.mt-xl-7,
.my-xl-7
{
margin-top: 6rem !important;
}
.mr-xl-7,
.mx-xl-7
{
margin-right: 6rem !important;
}
.mb-xl-7,
.my-xl-7
{
margin-bottom: 6rem !important;
}
.ml-xl-7,
.mx-xl-7
{
margin-left: 6rem !important;
}
.m-xl-8
{
margin: 8rem !important;
}
.mt-xl-8,
.my-xl-8
{
margin-top: 8rem !important;
}
.mr-xl-8,
.mx-xl-8
{
margin-right: 8rem !important;
}
.mb-xl-8,
.my-xl-8
{
margin-bottom: 8rem !important;
}
.ml-xl-8,
.mx-xl-8
{
margin-left: 8rem !important;
}
.m-xl-9
{
margin: 10rem !important;
}
.mt-xl-9,
.my-xl-9
{
margin-top: 10rem !important;
}
.mr-xl-9,
.mx-xl-9
{
margin-right: 10rem !important;
}
.mb-xl-9,
.my-xl-9
{
margin-bottom: 10rem !important;
}
.ml-xl-9,
.mx-xl-9
{
margin-left: 10rem !important;
}
.p-xl-0
{
padding: 0 !important;
}
.pt-xl-0,
.py-xl-0
{
padding-top: 0 !important;
}
.pr-xl-0,
.px-xl-0
{
padding-right: 0 !important;
}
.pb-xl-0,
.py-xl-0
{
padding-bottom: 0 !important;
}
.pl-xl-0,
.px-xl-0
{
padding-left: 0 !important;
}
.p-xl-1
{
padding: .25rem !important;
}
.pt-xl-1,
.py-xl-1
{
padding-top: .25rem !important;
}
.pr-xl-1,
.px-xl-1
{
padding-right: .25rem !important;
}
.pb-xl-1,
.py-xl-1
{
padding-bottom: .25rem !important;
}
.pl-xl-1,
.px-xl-1
{
padding-left: .25rem !important;
}
.p-xl-2
{
padding: .5rem !important;
}
.pt-xl-2,
.py-xl-2
{
padding-top: .5rem !important;
}
.pr-xl-2,
.px-xl-2
{
padding-right: .5rem !important;
}
.pb-xl-2,
.py-xl-2
{
padding-bottom: .5rem !important;
}
.pl-xl-2,
.px-xl-2
{
padding-left: .5rem !important;
}
.p-xl-3
{
padding: 1rem !important;
}
.pt-xl-3,
.py-xl-3
{
padding-top: 1rem !important;
}
.pr-xl-3,
.px-xl-3
{
padding-right: 1rem !important;
}
.pb-xl-3,
.py-xl-3
{
padding-bottom: 1rem !important;
}
.pl-xl-3,
.px-xl-3
{
padding-left: 1rem !important;
}
.p-xl-4
{
padding: 1.5rem !important;
}
.pt-xl-4,
.py-xl-4
{
padding-top: 1.5rem !important;
}
.pr-xl-4,
.px-xl-4
{
padding-right: 1.5rem !important;
}
.pb-xl-4,
.py-xl-4
{
padding-bottom: 1.5rem !important;
}
.pl-xl-4,
.px-xl-4
{
padding-left: 1.5rem !important;
}
.p-xl-5
{
padding: 3rem !important;
}
.pt-xl-5,
.py-xl-5
{
padding-top: 3rem !important;
}
.pr-xl-5,
.px-xl-5
{
padding-right: 3rem !important;
}
.pb-xl-5,
.py-xl-5
{
padding-bottom: 3rem !important;
}
.pl-xl-5,
.px-xl-5
{
padding-left: 3rem !important;
}
.p-xl--9
{
padding: -10rem !important;
}
.pt-xl--9,
.py-xl--9
{
padding-top: -10rem !important;
}
.pr-xl--9,
.px-xl--9
{
padding-right: -10rem !important;
}
.pb-xl--9,
.py-xl--9
{
padding-bottom: -10rem !important;
}
.pl-xl--9,
.px-xl--9
{
padding-left: -10rem !important;
}
.p-xl--8
{
padding: -8rem !important;
}
.pt-xl--8,
.py-xl--8
{
padding-top: -8rem !important;
}
.pr-xl--8,
.px-xl--8
{
padding-right: -8rem !important;
}
.pb-xl--8,
.py-xl--8
{
padding-bottom: -8rem !important;
}
.pl-xl--8,
.px-xl--8
{
padding-left: -8rem !important;
}
.p-xl--7
{
padding: -6rem !important;
}
.pt-xl--7,
.py-xl--7
{
padding-top: -6rem !important;
}
.pr-xl--7,
.px-xl--7
{
padding-right: -6rem !important;
}
.pb-xl--7,
.py-xl--7
{
padding-bottom: -6rem !important;
}
.pl-xl--7,
.px-xl--7
{
padding-left: -6rem !important;
}
.p-xl--6
{
padding: -4.5rem !important;
}
.pt-xl--6,
.py-xl--6
{
padding-top: -4.5rem !important;
}
.pr-xl--6,
.px-xl--6
{
padding-right: -4.5rem !important;
}
.pb-xl--6,
.py-xl--6
{
padding-bottom: -4.5rem !important;
}
.pl-xl--6,
.px-xl--6
{
padding-left: -4.5rem !important;
}
.p-xl--5
{
padding: -3rem !important;
}
.pt-xl--5,
.py-xl--5
{
padding-top: -3rem !important;
}
.pr-xl--5,
.px-xl--5
{
padding-right: -3rem !important;
}
.pb-xl--5,
.py-xl--5
{
padding-bottom: -3rem !important;
}
.pl-xl--5,
.px-xl--5
{
padding-left: -3rem !important;
}
.p-xl--4
{
padding: -1.5rem !important;
}
.pt-xl--4,
.py-xl--4
{
padding-top: -1.5rem !important;
}
.pr-xl--4,
.px-xl--4
{
padding-right: -1.5rem !important;
}
.pb-xl--4,
.py-xl--4
{
padding-bottom: -1.5rem !important;
}
.pl-xl--4,
.px-xl--4
{
padding-left: -1.5rem !important;
}
.p-xl--3
{
padding: -1rem !important;
}
.pt-xl--3,
.py-xl--3
{
padding-top: -1rem !important;
}
.pr-xl--3,
.px-xl--3
{
padding-right: -1rem !important;
}
.pb-xl--3,
.py-xl--3
{
padding-bottom: -1rem !important;
}
.pl-xl--3,
.px-xl--3
{
padding-left: -1rem !important;
}
.p-xl--2
{
padding: -.5rem !important;
}
.pt-xl--2,
.py-xl--2
{
padding-top: -.5rem !important;
}
.pr-xl--2,
.px-xl--2
{
padding-right: -.5rem !important;
}
.pb-xl--2,
.py-xl--2
{
padding-bottom: -.5rem !important;
}
.pl-xl--2,
.px-xl--2
{
padding-left: -.5rem !important;
}
.p-xl--1
{
padding: -.25rem !important;
}
.pt-xl--1,
.py-xl--1
{
padding-top: -.25rem !important;
}
.pr-xl--1,
.px-xl--1
{
padding-right: -.25rem !important;
}
.pb-xl--1,
.py-xl--1
{
padding-bottom: -.25rem !important;
}
.pl-xl--1,
.px-xl--1
{
padding-left: -.25rem !important;
}
.p-xl-6
{
padding: 4.5rem !important;
}
.pt-xl-6,
.py-xl-6
{
padding-top: 4.5rem !important;
}
.pr-xl-6,
.px-xl-6
{
padding-right: 4.5rem !important;
}
.pb-xl-6,
.py-xl-6
{
padding-bottom: 4.5rem !important;
}
.pl-xl-6,
.px-xl-6
{
padding-left: 4.5rem !important;
}
.p-xl-7
{
padding: 6rem !important;
}
.pt-xl-7,
.py-xl-7
{
padding-top: 6rem !important;
}
.pr-xl-7,
.px-xl-7
{
padding-right: 6rem !important;
}
.pb-xl-7,
.py-xl-7
{
padding-bottom: 6rem !important;
}
.pl-xl-7,
.px-xl-7
{
padding-left: 6rem !important;
}
.p-xl-8
{
padding: 8rem !important;
}
.pt-xl-8,
.py-xl-8
{
padding-top: 8rem !important;
}
.pr-xl-8,
.px-xl-8
{
padding-right: 8rem !important;
}
.pb-xl-8,
.py-xl-8
{
padding-bottom: 8rem !important;
}
.pl-xl-8,
.px-xl-8
{
padding-left: 8rem !important;
}
.p-xl-9
{
padding: 10rem !important;
}
.pt-xl-9,
.py-xl-9
{
padding-top: 10rem !important;
}
.pr-xl-9,
.px-xl-9
{
padding-right: 10rem !important;
}
.pb-xl-9,
.py-xl-9
{
padding-bottom: 10rem !important;
}
.pl-xl-9,
.px-xl-9
{
padding-left: 10rem !important;
}
.m-xl-auto
{
margin: auto !important;
}
.mt-xl-auto,
.my-xl-auto
{
margin-top: auto !important;
}
.mr-xl-auto,
.mx-xl-auto
{
margin-right: auto !important;
}
.mb-xl-auto,
.my-xl-auto
{
margin-bottom: auto !important;
}
.ml-xl-auto,
.mx-xl-auto
{
margin-left: auto !important;
}
}
.text-monospace
{
font-family: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
}
.text-justify
{
text-align: justify !important;
}
.text-nowrap
{
white-space: nowrap !important;
}
.text-truncate
{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.text-left
{
text-align: left !important;
}
.text-right
{
text-align: right !important;
}
.text-center
{
text-align: center !important;
}
@media (min-width: 576px)
{
.text-sm-left
{
text-align: left !important;
}
.text-sm-right
{
text-align: right !important;
}
.text-sm-center
{
text-align: center !important;
}
}
@media (min-width: 768px)
{
.text-md-left
{
text-align: left !important;
}
.text-md-right
{
text-align: right !important;
}
.text-md-center
{
text-align: center !important;
}
}
@media (min-width: 992px)
{
.text-lg-left
{
text-align: left !important;
}
.text-lg-right
{
text-align: right !important;
}
.text-lg-center
{
text-align: center !important;
}
}
@media (min-width: 1200px)
{
.text-xl-left
{
text-align: left !important;
}
.text-xl-right
{
text-align: right !important;
}
.text-xl-center
{
text-align: center !important;
}
}
.text-lowercase
{
text-transform: lowercase !important;
}
.text-uppercase
{
text-transform: uppercase !important;
}
.text-capitalize
{
text-transform: capitalize !important;
}
.font-weight-light
{
font-weight: 300 !important;
}
.font-weight-normal
{
font-weight: 400 !important;
}
.font-weight-bold
{
font-weight: 600 !important;
}
.font-italic
{
font-style: italic !important;
}
.text-white
{
color: #fff !important;
}
.text-primary
{
color: #5e72e4 !important;
}
a.text-primary:hover,
a.text-primary:focus
{
color: #324cdd !important;
}
.text-secondary
{
color: #f7fafc !important;
}
a.text-secondary:hover,
a.text-secondary:focus
{
color: #d2e3ee !important;
}
.text-success
{
color: #2dce89 !important;
}
a.text-success:hover,
a.text-success:focus
{
color: #24a46d !important;
}
.text-info
{
color: #11cdef !important;
}
a.text-info:hover,
a.text-info:focus
{
color: #0da5c0 !important;
}
.text-warning
{
color: #fb6340 !important;
}
a.text-warning:hover,
a.text-warning:focus
{
color: #fa3a0e !important;
}
.text-danger
{
color: #f5365c !important;
}
a.text-danger:hover,
a.text-danger:focus
{
color: #ec0c38 !important;
}
.text-light
{
color: #adb5bd !important;
}
a.text-light:hover,
a.text-light:focus
{
color: #919ca6 !important;
}
.text-dark
{
color: #212529 !important;
}
a.text-dark:hover,
a.text-dark:focus
{
color: #0a0c0d !important;
}
.text-default
{
color: #172b4d !important;
}
a.text-default:hover,
a.text-default:focus
{
color: #0b1526 !important;
}
.text-white
{
color: #fff !important;
}
a.text-white:hover,
a.text-white:focus
{
color: #e6e6e6 !important;
}
.text-neutral
{
color: #fff !important;
}
a.text-neutral:hover,
a.text-neutral:focus
{
color: #e6e6e6 !important;
}
.text-darker
{
color: black !important;
}
a.text-darker:hover,
a.text-darker:focus
{
color: black !important;
}
.text-body
{
color: #525f7f !important;
}
.text-muted
{
color: #8898aa !important;
}
.text-black-50
{
color: rgba(0, 0, 0, .5) !important;
}
.text-white-50
{
color: rgba(255, 255, 255, .5) !important;
}
.text-hide
{
font: 0/0 a;
color: transparent;
border: 0;
background-color: transparent;
text-shadow: none;
}
.visible
{
visibility: visible !important;
}
.invisible
{
visibility: hidden !important;
}
@media print
{
*,
*::before,
*::after
{
box-shadow: none !important;
text-shadow: none !important;
}
a:not(.btn)
{
text-decoration: underline;
}
abbr[title]::after
{
content: ' (' attr(title) ')';
}
pre
{
white-space: pre-wrap !important;
}
pre,
blockquote
{
border: 1px solid #adb5bd;
page-break-inside: avoid;
}
thead
{
display: table-header-group;
}
tr,
img
{
page-break-inside: avoid;
}
p,
h2,
h3
{
orphans: 3;
widows: 3;
}
h2,
h3
{
page-break-after: avoid;
}
@page
{
size: a3;
}
body
{
min-width: 992px !important;
}
.container
{
min-width: 992px !important;
}
.navbar
{
display: none;
}
.badge
{
border: 1px solid #000;
}
.table
{
border-collapse: collapse !important;
}
.table td,
.table th
{
background-color: #fff !important;
}
.table-bordered th,
.table-bordered td
{
border: 1px solid #dee2e6 !important;
}
.table-dark
{
color: inherit;
}
.table-dark th,
.table-dark td,
.table-dark thead th,
.table-dark tbody + tbody
{
border-color: #e9ecef;
}
.table .thead-dark th
{
color: inherit;
border-color: #e9ecef;
}
}
iframe
{
border: 0;
}
figcaption,
figure,
main
{
display: block;
}
main
{
overflow: hidden;
}
.bg-blue
{
background-color: #5e72e4 !important;
}
a.bg-blue:hover,
a.bg-blue:focus,
button.bg-blue:hover,
button.bg-blue:focus
{
background-color: #324cdd !important;
}
.bg-indigo
{
background-color: #5603ad !important;
}
a.bg-indigo:hover,
a.bg-indigo:focus,
button.bg-indigo:hover,
button.bg-indigo:focus
{
background-color: #3d027b !important;
}
.bg-purple
{
background-color: #8965e0 !important;
}
a.bg-purple:hover,
a.bg-purple:focus,
button.bg-purple:hover,
button.bg-purple:focus
{
background-color: #683bd7 !important;
}
.bg-pink
{
background-color: #f3a4b5 !important;
}
a.bg-pink:hover,
a.bg-pink:focus,
button.bg-pink:hover,
button.bg-pink:focus
{
background-color: #ed7790 !important;
}
.bg-red
{
background-color: #f5365c !important;
}
a.bg-red:hover,
a.bg-red:focus,
button.bg-red:hover,
button.bg-red:focus
{
background-color: #ec0c38 !important;
}
.bg-orange
{
background-color: #fb6340 !important;
}
a.bg-orange:hover,
a.bg-orange:focus,
button.bg-orange:hover,
button.bg-orange:focus
{
background-color: #fa3a0e !important;
}
.bg-yellow
{
background-color: #ffd600 !important;
}
a.bg-yellow:hover,
a.bg-yellow:focus,
button.bg-yellow:hover,
button.bg-yellow:focus
{
background-color: #ccab00 !important;
}
.bg-green
{
background-color: #2dce89 !important;
}
a.bg-green:hover,
a.bg-green:focus,
button.bg-green:hover,
button.bg-green:focus
{
background-color: #24a46d !important;
}
.bg-teal
{
background-color: #11cdef !important;
}
a.bg-teal:hover,
a.bg-teal:focus,
button.bg-teal:hover,
button.bg-teal:focus
{
background-color: #0da5c0 !important;
}
.bg-cyan
{
background-color: #2bffc6 !important;
}
a.bg-cyan:hover,
a.bg-cyan:focus,
button.bg-cyan:hover,
button.bg-cyan:focus
{
background-color: #00f7b5 !important;
}
.bg-white
{
background-color: #fff !important;
}
a.bg-white:hover,
a.bg-white:focus,
button.bg-white:hover,
button.bg-white:focus
{
background-color: #e6e6e6 !important;
}
.bg-gray
{
background-color: #8898aa !important;
}
a.bg-gray:hover,
a.bg-gray:focus,
button.bg-gray:hover,
button.bg-gray:focus
{
background-color: #6a7e95 !important;
}
.bg-gray-dark
{
background-color: #32325d !important;
}
a.bg-gray-dark:hover,
a.bg-gray-dark:focus,
button.bg-gray-dark:hover,
button.bg-gray-dark:focus
{
background-color: #20203c !important;
}
.bg-light
{
background-color: #ced4da !important;
}
a.bg-light:hover,
a.bg-light:focus,
button.bg-light:hover,
button.bg-light:focus
{
background-color: #b1bbc4 !important;
}
.bg-lighter
{
background-color: #e9ecef !important;
}
a.bg-lighter:hover,
a.bg-lighter:focus,
button.bg-lighter:hover,
button.bg-lighter:focus
{
background-color: #cbd3da !important;
}
.bg-gradient-primary
{
background: linear-gradient(87deg, #5e72e4 0, #825ee4 100%) !important;
}
.bg-gradient-secondary
{
background: linear-gradient(87deg, #f7fafc 0, #f7f8fc 100%) !important;
}
.bg-gradient-success
{
background: linear-gradient(87deg, #2dce89 0, #2dcecc 100%) !important;
}
.bg-gradient-info
{
background: linear-gradient(87deg, #11cdef 0, #1171ef 100%) !important;
}
.bg-gradient-warning
{
background: linear-gradient(87deg, #fb6340 0, #fbb140 100%) !important;
}
.bg-gradient-danger
{
background: linear-gradient(87deg, #f5365c 0, #f56036 100%) !important;
}
.bg-gradient-light
{
background: linear-gradient(87deg, #adb5bd 0, #adaebd 100%) !important;
}
.bg-gradient-dark
{
background: linear-gradient(87deg, #212529 0, #212229 100%) !important;
}
.bg-gradient-default
{
background: linear-gradient(87deg, #172b4d 0, #1a174d 100%) !important;
}
.bg-gradient-white
{
background: linear-gradient(87deg, #fff 0, white 100%) !important;
}
.bg-gradient-neutral
{
background: linear-gradient(87deg, #fff 0, white 100%) !important;
}
.bg-gradient-darker
{
background: linear-gradient(87deg, black 0, black 100%) !important;
}
.bg-gradient-blue
{
background: linear-gradient(87deg, #5e72e4 0, #825ee4 100%) !important;
}
.bg-gradient-indigo
{
background: linear-gradient(87deg, #5603ad 0, #9d03ad 100%) !important;
}
.bg-gradient-purple
{
background: linear-gradient(87deg, #8965e0 0, #bc65e0 100%) !important;
}
.bg-gradient-pink
{
background: linear-gradient(87deg, #f3a4b5 0, #f3b4a4 100%) !important;
}
.bg-gradient-red
{
background: linear-gradient(87deg, #f5365c 0, #f56036 100%) !important;
}
.bg-gradient-orange
{
background: linear-gradient(87deg, #fb6340 0, #fbb140 100%) !important;
}
.bg-gradient-yellow
{
background: linear-gradient(87deg, #ffd600 0, #beff00 100%) !important;
}
.bg-gradient-green
{
background: linear-gradient(87deg, #2dce89 0, #2dcecc 100%) !important;
}
.bg-gradient-teal
{
background: linear-gradient(87deg, #11cdef 0, #1171ef 100%) !important;
}
.bg-gradient-cyan
{
background: linear-gradient(87deg, #2bffc6 0, #2be0ff 100%) !important;
}
.bg-gradient-white
{
background: linear-gradient(87deg, #fff 0, white 100%) !important;
}
.bg-gradient-gray
{
background: linear-gradient(87deg, #8898aa 0, #888aaa 100%) !important;
}
.bg-gradient-gray-dark
{
background: linear-gradient(87deg, #32325d 0, #44325d 100%) !important;
}
.bg-gradient-light
{
background: linear-gradient(87deg, #ced4da 0, #cecfda 100%) !important;
}
.bg-gradient-lighter
{
background: linear-gradient(87deg, #e9ecef 0, #e9eaef 100%) !important;
}
.bg-translucent-primary
{
background-color: rgba(63, 87, 223, .6) !important;
}
a.bg-translucent-primary:hover,
a.bg-translucent-primary:focus,
button.bg-translucent-primary:hover,
button.bg-translucent-primary:focus
{
background-color: rgba(42, 68, 219, .6) !important;
}
.bg-translucent-secondary
{
background-color: rgba(221, 234, 242, .6) !important;
}
a.bg-translucent-secondary:hover,
a.bg-translucent-secondary:focus,
button.bg-translucent-secondary:hover,
button.bg-translucent-secondary:focus
{
background-color: rgba(202, 222, 235, .6) !important;
}
.bg-translucent-success
{
background-color: rgba(39, 177, 118, .6) !important;
}
a.bg-translucent-success:hover,
a.bg-translucent-success:focus,
button.bg-translucent-success:hover,
button.bg-translucent-success:focus
{
background-color: rgba(34, 156, 104, .6) !important;
}
.bg-translucent-info
{
background-color: rgba(14, 177, 206, .6) !important;
}
a.bg-translucent-info:hover,
a.bg-translucent-info:focus,
button.bg-translucent-info:hover,
button.bg-translucent-info:focus
{
background-color: rgba(12, 156, 183, .6) !important;
}
.bg-translucent-warning
{
background-color: rgba(250, 70, 29, .6) !important;
}
a.bg-translucent-warning:hover,
a.bg-translucent-warning:focus,
button.bg-translucent-warning:hover,
button.bg-translucent-warning:focus
{
background-color: rgba(249, 51, 5, .6) !important;
}
.bg-translucent-danger
{
background-color: rgba(243, 20, 64, .6) !important;
}
a.bg-translucent-danger:hover,
a.bg-translucent-danger:focus,
button.bg-translucent-danger:hover,
button.bg-translucent-danger:focus
{
background-color: rgba(227, 11, 54, .6) !important;
}
.bg-translucent-light
{
background-color: rgba(153, 163, 173, .6) !important;
}
a.bg-translucent-light:hover,
a.bg-translucent-light:focus,
button.bg-translucent-light:hover,
button.bg-translucent-light:focus
{
background-color: rgba(139, 150, 162, .6) !important;
}
.bg-translucent-dark
{
background-color: rgba(17, 19, 21, .6) !important;
}
a.bg-translucent-dark:hover,
a.bg-translucent-dark:focus,
button.bg-translucent-dark:hover,
button.bg-translucent-dark:focus
{
background-color: rgba(6, 6, 7, .6) !important;
}
.bg-translucent-default
{
background-color: rgba(15, 28, 50, .6) !important;
}
a.bg-translucent-default:hover,
a.bg-translucent-default:focus,
button.bg-translucent-default:hover,
button.bg-translucent-default:focus
{
background-color: rgba(9, 17, 30, .6) !important;
}
.bg-translucent-white
{
background-color: rgba(237, 237, 237, .6) !important;
}
a.bg-translucent-white:hover,
a.bg-translucent-white:focus,
button.bg-translucent-white:hover,
button.bg-translucent-white:focus
{
background-color: rgba(224, 224, 224, .6) !important;
}
.bg-translucent-neutral
{
background-color: rgba(237, 237, 237, .6) !important;
}
a.bg-translucent-neutral:hover,
a.bg-translucent-neutral:focus,
button.bg-translucent-neutral:hover,
button.bg-translucent-neutral:focus
{
background-color: rgba(224, 224, 224, .6) !important;
}
.bg-translucent-darker
{
background-color: rgba(0, 0, 0, .6) !important;
}
a.bg-translucent-darker:hover,
a.bg-translucent-darker:focus,
button.bg-translucent-darker:hover,
button.bg-translucent-darker:focus
{
background-color: rgba(0, 0, 0, .6) !important;
}
.section-primary
{
background-color: #f8f9fe !important;
}
a.section-primary:hover,
a.section-primary:focus,
button.section-primary:hover,
button.section-primary:focus
{
background-color: #cbd3f8 !important;
}
.section-secondary
{
background-color: #f7fafc !important;
}
a.section-secondary:hover,
a.section-secondary:focus,
button.section-secondary:hover,
button.section-secondary:focus
{
background-color: #d2e3ee !important;
}
.section-light
{
background-color: #ced4da !important;
}
a.section-light:hover,
a.section-light:focus,
button.section-light:hover,
button.section-light:focus
{
background-color: #b1bbc4 !important;
}
.section-dark
{
background-color: #212529 !important;
}
a.section-dark:hover,
a.section-dark:focus,
button.section-dark:hover,
button.section-dark:focus
{
background-color: #0a0c0d !important;
}
.section-darker
{
background-color: black !important;
}
a.section-darker:hover,
a.section-darker:focus,
button.section-darker:hover,
button.section-darker:focus
{
background-color: black !important;
}
.bg-gradient-primary
{
background: linear-gradient(87deg, #5e72e4 0, #825ee4 100%) !important;
}
.bg-gradient-secondary
{
background: linear-gradient(87deg, #f7fafc 0, #f7f8fc 100%) !important;
}
.bg-gradient-success
{
background: linear-gradient(87deg, #2dce89 0, #2dcecc 100%) !important;
}
.bg-gradient-info
{
background: linear-gradient(87deg, #11cdef 0, #1171ef 100%) !important;
}
.bg-gradient-warning
{
background: linear-gradient(87deg, #fb6340 0, #fbb140 100%) !important;
}
.bg-gradient-danger
{
background: linear-gradient(87deg, #f5365c 0, #f56036 100%) !important;
}
.bg-gradient-light
{
background: linear-gradient(87deg, #adb5bd 0, #adaebd 100%) !important;
}
.bg-gradient-dark
{
background: linear-gradient(87deg, #212529 0, #212229 100%) !important;
}
.bg-gradient-default
{
background: linear-gradient(87deg, #172b4d 0, #1a174d 100%) !important;
}
.bg-gradient-white
{
background: linear-gradient(87deg, #fff 0, white 100%) !important;
}
.bg-gradient-neutral
{
background: linear-gradient(87deg, #fff 0, white 100%) !important;
}
.bg-gradient-darker
{
background: linear-gradient(87deg, black 0, black 100%) !important;
}
.fill-primary
{
fill: #5e72e4;
}
.stroke-primary
{
stroke: #5e72e4;
}
.fill-secondary
{
fill: #f7fafc;
}
.stroke-secondary
{
stroke: #f7fafc;
}
.fill-success
{
fill: #2dce89;
}
.stroke-success
{
stroke: #2dce89;
}
.fill-info
{
fill: #11cdef;
}
.stroke-info
{
stroke: #11cdef;
}
.fill-warning
{
fill: #fb6340;
}
.stroke-warning
{
stroke: #fb6340;
}
.fill-danger
{
fill: #f5365c;
}
.stroke-danger
{
stroke: #f5365c;
}
.fill-light
{
fill: #adb5bd;
}
.stroke-light
{
stroke: #adb5bd;
}
.fill-dark
{
fill: #212529;
}
.stroke-dark
{
stroke: #212529;
}
.fill-default
{
fill: #172b4d;
}
.stroke-default
{
stroke: #172b4d;
}
.fill-white
{
fill: #fff;
}
.stroke-white
{
stroke: #fff;
}
.fill-neutral
{
fill: #fff;
}
.stroke-neutral
{
stroke: #fff;
}
.fill-darker
{
fill: black;
}
.stroke-darker
{
stroke: black;
}
.fill-opacity-8
{
fill-opacity: .8;
}
.floating
{
animation: floating 3s ease infinite;
will-change: transform;
}
.floating:hover
{
animation-play-state: paused;
}
.floating-lg
{
animation: floating-lg 3s ease infinite;
}
.floating-sm
{
animation: floating-sm 3s ease infinite;
}
@keyframes floating-lg
{
0%
{
transform: translateY(0px);
}
50%
{
transform: translateY(15px);
}
100%
{
transform: translateY(0px);
}
}
@keyframes floating
{
0%
{
transform: translateY(0px);
}
50%
{
transform: translateY(10px);
}
100%
{
transform: translateY(0px);
}
}
@keyframes floating-sm
{
0%
{
transform: translateY(0px);
}
50%
{
transform: translateY(5px);
}
100%
{
transform: translateY(0px);
}
}
.floatfix:before,
.floatfix:after
{
display: table;
content: '';
}
.floatfix:after
{
clear: both;
}
.img-center
{
display: block;
margin-right: auto;
margin-left: auto;
}
.opacity-1
{
opacity: .1 !important;
}
.opacity-2
{
opacity: .2 !important;
}
.opacity-3
{
opacity: .3 !important;
}
.opacity-4
{
opacity: .4 !important;
}
.opacity-5
{
opacity: .5 !important;
}
.opacity-6
{
opacity: .6 !important;
}
.opacity-7
{
opacity: .7 !important;
}
.opacity-8
{
opacity: .8 !important;
}
.opacity-8
{
opacity: .9 !important;
}
.opacity-10
{
opacity: 1 !important;
}
.overflow-visible
{
overflow: visible !important;
}
.overflow-hidden
{
overflow: hidden !important;
}
.top-0
{
top: 0;
}
.right-0
{
right: 0;
}
.bottom-0
{
bottom: 0;
}
.left-0
{
left: 0;
}
.top-1
{
top: .25rem;
}
.right-1
{
right: .25rem;
}
.bottom-1
{
bottom: .25rem;
}
.left-1
{
left: .25rem;
}
.top-2
{
top: .5rem;
}
.right-2
{
right: .5rem;
}
.bottom-2
{
bottom: .5rem;
}
.left-2
{
left: .5rem;
}
.top-3
{
top: 1rem;
}
.right-3
{
right: 1rem;
}
.bottom-3
{
bottom: 1rem;
}
.left-3
{
left: 1rem;
}
.top-4
{
top: 1.5rem;
}
.right-4
{
right: 1.5rem;
}
.bottom-4
{
bottom: 1.5rem;
}
.left-4
{
left: 1.5rem;
}
.top-5
{
top: 3rem;
}
.right-5
{
right: 3rem;
}
.bottom-5
{
bottom: 3rem;
}
.left-5
{
left: 3rem;
}
.top--9
{
top: -10rem;
}
.right--9
{
right: -10rem;
}
.bottom--9
{
bottom: -10rem;
}
.left--9
{
left: -10rem;
}
.top--8
{
top: -8rem;
}
.right--8
{
right: -8rem;
}
.bottom--8
{
bottom: -8rem;
}
.left--8
{
left: -8rem;
}
.top--7
{
top: -6rem;
}
.right--7
{
right: -6rem;
}
.bottom--7
{
bottom: -6rem;
}
.left--7
{
left: -6rem;
}
.top--6
{
top: -4.5rem;
}
.right--6
{
right: -4.5rem;
}
.bottom--6
{
bottom: -4.5rem;
}
.left--6
{
left: -4.5rem;
}
.top--5
{
top: -3rem;
}
.right--5
{
right: -3rem;
}
.bottom--5
{
bottom: -3rem;
}
.left--5
{
left: -3rem;
}
.top--4
{
top: -1.5rem;
}
.right--4
{
right: -1.5rem;
}
.bottom--4
{
bottom: -1.5rem;
}
.left--4
{
left: -1.5rem;
}
.top--3
{
top: -1rem;
}
.right--3
{
right: -1rem;
}
.bottom--3
{
bottom: -1rem;
}
.left--3
{
left: -1rem;
}
.top--2
{
top: -.5rem;
}
.right--2
{
right: -.5rem;
}
.bottom--2
{
bottom: -.5rem;
}
.left--2
{
left: -.5rem;
}
.top--1
{
top: -.25rem;
}
.right--1
{
right: -.25rem;
}
.bottom--1
{
bottom: -.25rem;
}
.left--1
{
left: -.25rem;
}
.top-6
{
top: 4.5rem;
}
.right-6
{
right: 4.5rem;
}
.bottom-6
{
bottom: 4.5rem;
}
.left-6
{
left: 4.5rem;
}
.top-7
{
top: 6rem;
}
.right-7
{
right: 6rem;
}
.bottom-7
{
bottom: 6rem;
}
.left-7
{
left: 6rem;
}
.top-8
{
top: 8rem;
}
.right-8
{
right: 8rem;
}
.bottom-8
{
bottom: 8rem;
}
.left-8
{
left: 8rem;
}
.top-9
{
top: 10rem;
}
.right-9
{
right: 10rem;
}
.bottom-9
{
bottom: 10rem;
}
.left-9
{
left: 10rem;
}
.center
{
left: 50%;
transform: translateX(-50%);
}
.h-100vh
{
height: 100vh !important;
}
.row.row-grid > [class*='col-'] + [class*='col-']
{
margin-top: 3rem;
}
@media (min-width: 992px)
{
.row.row-grid > [class*='col-lg-'] + [class*='col-lg-']
{
margin-top: 0;
}
}
@media (min-width: 768px)
{
.row.row-grid > [class*='col-md-'] + [class*='col-md-']
{
margin-top: 0;
}
}
@media (min-width: 576px)
{
.row.row-grid > [class*='col-sm-'] + [class*='col-sm-']
{
margin-top: 0;
}
}
.row-grid + .row-grid
{
margin-top: 3rem;
}
@media (min-width: 992px)
{
.mt--100
{
margin-top: -100px !important;
}
.mr--100
{
margin-right: -100px !important;
}
.mb--100
{
margin-bottom: -100px !important;
}
.ml--100
{
margin-left: -100px !important;
}
.mt--150
{
margin-top: -150px !important;
}
.mb--150
{
margin-bottom: -150px !important;
}
.mt--200
{
margin-top: -200px !important;
}
.mb--200
{
margin-bottom: -200px !important;
}
.mt--300
{
margin-top: -300px !important;
}
.mb--300
{
margin-bottom: -300px !important;
}
.pt-100
{
padding-top: 100px !important;
}
.pb-100
{
padding-bottom: 100px !important;
}
.pt-150
{
padding-top: 150px !important;
}
.pb-150
{
padding-bottom: 150px !important;
}
.pt-200
{
padding-top: 200px !important;
}
.pb-200
{
padding-bottom: 200px !important;
}
.pt-250
{
padding-top: 250px !important;
}
.pb-250
{
padding-bottom: 250px !important;
}
.pt-300
{
padding-top: 300px !important;
}
.pb-300
{
padding-bottom: 300px !important;
}
}
[class*='shadow']
{
transition: all .15s ease;
}
.shadow-sm--hover:hover
{
box-shadow: 0 0 .5rem rgba(136, 152, 170, .075) !important;
}
.shadow--hover:hover
{
box-shadow: 0 0 2rem 0 rgba(136, 152, 170, .15) !important;
}
.shadow-lg--hover:hover
{
box-shadow: 0 0 3rem rgba(136, 152, 170, .175) !important;
}
.shadow-none--hover:hover
{
box-shadow: none !important;
}
.font-weight-300
{
font-weight: 300 !important;
}
.font-weight-400
{
font-weight: 400 !important;
}
.font-weight-500
{
font-weight: 500 !important;
}
.font-weight-600
{
font-weight: 600 !important;
}
.font-weight-700
{
font-weight: 700 !important;
}
.font-weight-800
{
font-weight: 800 !important;
}
.font-weight-900
{
font-weight: 900 !important;
}
.text-underline
{
text-decoration: underline;
}
.text-through
{
text-decoration: line-through;
}
.text-xs
{
font-size: .75rem !important;
}
.text-sm
{
font-size: .875rem !important;
}
.text-lg
{
font-size: 1.25rem !important;
}
.text-xl
{
font-size: 1.5rem !important;
}
.lh-100
{
line-height: 1;
}
.lh-110
{
line-height: 1.1;
}
.lh-120
{
line-height: 1.2;
}
.lh-130
{
line-height: 1.3;
}
.lh-140
{
line-height: 1.4;
}
.lh-150
{
line-height: 1.5;
}
.lh-160
{
line-height: 1.6;
}
.lh-170
{
line-height: 1.7;
}
.lh-180
{
line-height: 1.8;
}
.ls-1
{
letter-spacing: .0625rem;
}
.ls-15
{
letter-spacing: .09375rem;
}
.ls-2
{
letter-spacing: .125rem;
}
.text-blue
{
color: #5e72e4 !important;
}
a.text-blue:hover,
a.text-blue:focus
{
color: #324cdd !important;
}
.text-indigo
{
color: #5603ad !important;
}
a.text-indigo:hover,
a.text-indigo:focus
{
color: #3d027b !important;
}
.text-purple
{
color: #8965e0 !important;
}
a.text-purple:hover,
a.text-purple:focus
{
color: #683bd7 !important;
}
.text-pink
{
color: #f3a4b5 !important;
}
a.text-pink:hover,
a.text-pink:focus
{
color: #ed7790 !important;
}
.text-red
{
color: #f5365c !important;
}
a.text-red:hover,
a.text-red:focus
{
color: #ec0c38 !important;
}
.text-orange
{
color: #fb6340 !important;
}
a.text-orange:hover,
a.text-orange:focus
{
color: #fa3a0e !important;
}
.text-yellow
{
color: #ffd600 !important;
}
a.text-yellow:hover,
a.text-yellow:focus
{
color: #ccab00 !important;
}
.text-green
{
color: #2dce89 !important;
}
a.text-green:hover,
a.text-green:focus
{
color: #24a46d !important;
}
.text-teal
{
color: #11cdef !important;
}
a.text-teal:hover,
a.text-teal:focus
{
color: #0da5c0 !important;
}
.text-cyan
{
color: #2bffc6 !important;
}
a.text-cyan:hover,
a.text-cyan:focus
{
color: #00f7b5 !important;
}
.text-white
{
color: #fff !important;
}
a.text-white:hover,
a.text-white:focus
{
color: #e6e6e6 !important;
}
.text-gray
{
color: #8898aa !important;
}
a.text-gray:hover,
a.text-gray:focus
{
color: #6a7e95 !important;
}
.text-gray-dark
{
color: #32325d !important;
}
a.text-gray-dark:hover,
a.text-gray-dark:focus
{
color: #20203c !important;
}
.text-light
{
color: #ced4da !important;
}
a.text-light:hover,
a.text-light:focus
{
color: #b1bbc4 !important;
}
.text-lighter
{
color: #e9ecef !important;
}
a.text-lighter:hover,
a.text-lighter:focus
{
color: #cbd3da !important;
}
@media (min-width: 992px)
{
.transform-perspective-right
{
transform: scale(1) perspective(1040px) rotateY(-11deg) rotateX(2deg) rotate(2deg);
}
.transform-perspective-left
{
transform: scale(1) perspective(2000px) rotateY(11deg) rotateX(2deg) rotate(-2deg);
}
}
.alert
{
font-size: .875rem;
}
.alert-heading
{
font-size: .9375rem;
font-weight: 600;
margin-top: .15rem;
}
.alert-icon
{
font-size: 1.25rem;
display: inline-block;
margin-right: 1.25rem;
vertical-align: middle;
}
.alert-icon i.ni
{
position: relative;
top: 1px;
}
.alert-text
{
display: inline-block;
vertical-align: middle;
}
[class*='alert-'] .alert-link
{
color: #fff;
border-bottom: 1px dotted rgba(255, 255, 255, .5);
}
.alert-dismissible .close
{
top: 50%;
right: 1.5rem;
padding: 0;
transform: translateY(-50%);
opacity: 1;
color: rgba(255, 255, 255, .6);
}
.alert-dismissible .close:hover,
.alert-dismissible .close:focus
{
opacity: 1 !important;
color: rgba(255, 255, 255, .9);
}
@media (max-width: 575.98px)
{
.alert-dismissible .close
{
top: 1rem;
right: .5rem;
}
}
.alert-dismissible .close > span:not(.sr-only)
{
font-size: 1.5rem;
color: rgba(255, 255, 255, .6);
background-color: transparent;
}
.alert-dismissible .close:hover > span:not(.sr-only),
.alert-dismissible .close:focus > span:not(.sr-only)
{
color: rgba(255, 255, 255, .9);
background-color: transparent;
}
.avatar
{
font-size: 1rem;
display: inline-flex;
width: 48px;
height: 48px;
color: #fff;
border-radius: 50%;
background-color: #adb5bd;
align-items: center;
justify-content: center;
}
.avatar img
{
width: 100%;
border-radius: 50%;
}
.avatar + .avatar-content
{
display: inline-block;
margin-left: .75rem;
}
.avatar-lg
{
font-size: .875rem;
width: 58px;
height: 58px;
}
.avatar-sm
{
font-size: .875rem;
width: 36px;
height: 36px;
}
.avatar-group .avatar
{
position: relative;
z-index: 2;
border: 2px solid #fff;
}
.avatar-group .avatar:hover
{
z-index: 3;
}
.avatar-group .avatar + .avatar
{
margin-left: -1rem;
}
.badge
{
text-transform: uppercase;
}
.badge a
{
color: #fff;
}
.badge-md
{
padding: .65em 1em;
}
.badge-lg
{
padding: .85em 1.375em;
}
.badge-inline
{
margin-right: .625rem;
}
.badge-inline + span
{
position: relative;
top: 2px;
}
.badge-inline + span > a
{
text-decoration: underline;
}
.btn .badge:not(:first-child)
{
margin-left: .5rem;
}
.btn .badge:not(:last-child)
{
margin-right: .5rem;
}
.badge-circle
{
font-size: .875rem;
display: inline-flex;
width: 2rem;
height: 2rem;
text-align: center;
border-radius: 50%;
align-items: center;
justify-content: center;
}
.badge-dot
{
font-size: .875rem;
font-weight: 400;
padding-right: 0;
padding-left: 0;
text-transform: none;
background: transparent;
}
.badge-dot strong
{
color: #32325d;
}
.badge-dot i
{
display: inline-block;
width: .375rem;
height: .375rem;
margin-right: .375rem;
vertical-align: middle;
border-radius: 50%;
}
.badge-dot.badge-md i
{
width: .5rem;
height: .5rem;
}
.badge-dot.badge-lg i
{
width: .625rem;
height: .625rem;
}
.btn
{
font-size: .875rem;
position: relative;
transition: all .15s ease;
letter-spacing: .025em;
text-transform: none;
will-change: transform;
}
.btn:hover
{
transform: translateY(-1px);
box-shadow: 0 7px 14px rgba(50, 50, 93, .1), 0 3px 6px rgba(0, 0, 0, .08);
}
.btn:not(:last-child)
{
margin-right: .5rem;
}
.btn i:not(:first-child),
.btn svg:not(:first-child)
{
margin-left: .5rem;
}
.btn i:not(:last-child),
.btn svg:not(:last-child)
{
margin-right: .5rem;
}
.btn-group .btn,
.input-group .btn
{
margin-right: 0;
transform: translateY(0);
}
.btn-sm,
.btn-group-sm > .btn
{
font-size: .75rem;
}
.btn-lg,
.btn-group-lg > .btn
{
font-size: .875rem;
}
[class*='btn-outline-']
{
border-width: 1px;
}
.btn-outline-secondary
{
color: #4385b1;
}
.btn-inner--icon i:not(.fa)
{
position: relative;
top: 2px;
}
.btn-link
{
font-weight: 600;
box-shadow: none;
}
.btn-link:hover
{
transform: none;
box-shadow: none;
}
.btn-neutral
{
color: #5e72e4;
}
.btn-icon .btn-inner--icon img
{
width: 20px;
}
.btn-icon .btn-inner--text:not(:first-child)
{
margin-left: .75em;
}
.btn-icon .btn-inner--text:not(:last-child)
{
margin-right: .75em;
}
.btn-icon-only
{
width: 2.375rem;
height: 2.375rem;
padding: 0;
}
a.btn-icon-only
{
line-height: 2.5;
}
.btn-icon-only.btn-sm,
.btn-group-sm > .btn-icon-only.btn
{
width: 2rem;
height: 2rem;
}
.btn-icon-clipboard
{
font-family: inherit;
font-size: 1rem;
font-weight: 400;
line-height: 1.25;
display: inline-block;
width: 100%;
margin: 0;
margin: .5rem 0;
padding: 1.5rem;
cursor: pointer;
text-align: left;
vertical-align: middle;
text-decoration: none;
color: #32325d;
border: 0;
border-radius: .375rem;
background-color: #f6f9fc;
-moz-appearance: none;
}
.btn-icon-clipboard:hover
{
background-color: #fff;
box-shadow: rgba(0, 0, 0, .1) 0 0 0 1px, rgba(0, 0, 0, .1) 0 4px 16px;
}
.btn-icon-clipboard > div
{
display: flex;
align-items: center;
}
.btn-icon-clipboard i
{
font-size: 1.5rem;
box-sizing: content-box;
vertical-align: middle;
color: #5e72e4;
}
.btn-icon-clipboard span
{
font-size: .875rem;
line-height: 1.5;
display: inline-block;
overflow: hidden;
margin-left: 16px;
vertical-align: middle;
white-space: nowrap;
text-overflow: ellipsis;
}
.btn-facebook
{
color: #fff;
border-color: #3b5999;
background-color: #3b5999;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-facebook:hover
{
color: #fff;
border-color: #3b5999;
background-color: #3b5999;
}
.btn-facebook:focus,
.btn-facebook.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(59, 89, 153, .5);
}
.btn-facebook.disabled,
.btn-facebook:disabled
{
color: #fff;
border-color: #3b5999;
background-color: #3b5999;
}
.btn-facebook:not(:disabled):not(.disabled):active,
.btn-facebook:not(:disabled):not(.disabled).active,
.show > .btn-facebook.dropdown-toggle
{
color: #fff;
border-color: #3b5999;
background-color: #2d4474;
}
.btn-facebook:not(:disabled):not(.disabled):active:focus,
.btn-facebook:not(:disabled):not(.disabled).active:focus,
.show > .btn-facebook.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(59, 89, 153, .5);
}
.btn-twitter
{
color: #fff;
border-color: #1da1f2;
background-color: #1da1f2;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-twitter:hover
{
color: #fff;
border-color: #1da1f2;
background-color: #1da1f2;
}
.btn-twitter:focus,
.btn-twitter.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(29, 161, 242, .5);
}
.btn-twitter.disabled,
.btn-twitter:disabled
{
color: #fff;
border-color: #1da1f2;
background-color: #1da1f2;
}
.btn-twitter:not(:disabled):not(.disabled):active,
.btn-twitter:not(:disabled):not(.disabled).active,
.show > .btn-twitter.dropdown-toggle
{
color: #fff;
border-color: #1da1f2;
background-color: #0c85d0;
}
.btn-twitter:not(:disabled):not(.disabled):active:focus,
.btn-twitter:not(:disabled):not(.disabled).active:focus,
.show > .btn-twitter.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(29, 161, 242, .5);
}
.btn-google-plus
{
color: #fff;
border-color: #dd4b39;
background-color: #dd4b39;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-google-plus:hover
{
color: #fff;
border-color: #dd4b39;
background-color: #dd4b39;
}
.btn-google-plus:focus,
.btn-google-plus.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(221, 75, 57, .5);
}
.btn-google-plus.disabled,
.btn-google-plus:disabled
{
color: #fff;
border-color: #dd4b39;
background-color: #dd4b39;
}
.btn-google-plus:not(:disabled):not(.disabled):active,
.btn-google-plus:not(:disabled):not(.disabled).active,
.show > .btn-google-plus.dropdown-toggle
{
color: #fff;
border-color: #dd4b39;
background-color: #c23321;
}
.btn-google-plus:not(:disabled):not(.disabled):active:focus,
.btn-google-plus:not(:disabled):not(.disabled).active:focus,
.show > .btn-google-plus.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(221, 75, 57, .5);
}
.btn-instagram
{
color: #fff;
border-color: #e4405f;
background-color: #e4405f;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-instagram:hover
{
color: #fff;
border-color: #e4405f;
background-color: #e4405f;
}
.btn-instagram:focus,
.btn-instagram.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(228, 64, 95, .5);
}
.btn-instagram.disabled,
.btn-instagram:disabled
{
color: #fff;
border-color: #e4405f;
background-color: #e4405f;
}
.btn-instagram:not(:disabled):not(.disabled):active,
.btn-instagram:not(:disabled):not(.disabled).active,
.show > .btn-instagram.dropdown-toggle
{
color: #fff;
border-color: #e4405f;
background-color: #d31e40;
}
.btn-instagram:not(:disabled):not(.disabled):active:focus,
.btn-instagram:not(:disabled):not(.disabled).active:focus,
.show > .btn-instagram.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(228, 64, 95, .5);
}
.btn-pinterest
{
color: #fff;
border-color: #bd081c;
background-color: #bd081c;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-pinterest:hover
{
color: #fff;
border-color: #bd081c;
background-color: #bd081c;
}
.btn-pinterest:focus,
.btn-pinterest.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(189, 8, 28, .5);
}
.btn-pinterest.disabled,
.btn-pinterest:disabled
{
color: #fff;
border-color: #bd081c;
background-color: #bd081c;
}
.btn-pinterest:not(:disabled):not(.disabled):active,
.btn-pinterest:not(:disabled):not(.disabled).active,
.show > .btn-pinterest.dropdown-toggle
{
color: #fff;
border-color: #bd081c;
background-color: #8c0615;
}
.btn-pinterest:not(:disabled):not(.disabled):active:focus,
.btn-pinterest:not(:disabled):not(.disabled).active:focus,
.show > .btn-pinterest.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(189, 8, 28, .5);
}
.btn-youtube
{
color: #fff;
border-color: #cd201f;
background-color: #cd201f;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-youtube:hover
{
color: #fff;
border-color: #cd201f;
background-color: #cd201f;
}
.btn-youtube:focus,
.btn-youtube.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(205, 32, 31, .5);
}
.btn-youtube.disabled,
.btn-youtube:disabled
{
color: #fff;
border-color: #cd201f;
background-color: #cd201f;
}
.btn-youtube:not(:disabled):not(.disabled):active,
.btn-youtube:not(:disabled):not(.disabled).active,
.show > .btn-youtube.dropdown-toggle
{
color: #fff;
border-color: #cd201f;
background-color: #a11918;
}
.btn-youtube:not(:disabled):not(.disabled):active:focus,
.btn-youtube:not(:disabled):not(.disabled).active:focus,
.show > .btn-youtube.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(205, 32, 31, .5);
}
.btn-slack
{
color: #fff;
border-color: #3aaf85;
background-color: #3aaf85;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-slack:hover
{
color: #fff;
border-color: #3aaf85;
background-color: #3aaf85;
}
.btn-slack:focus,
.btn-slack.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(58, 175, 133, .5);
}
.btn-slack.disabled,
.btn-slack:disabled
{
color: #fff;
border-color: #3aaf85;
background-color: #3aaf85;
}
.btn-slack:not(:disabled):not(.disabled):active,
.btn-slack:not(:disabled):not(.disabled).active,
.show > .btn-slack.dropdown-toggle
{
color: #fff;
border-color: #3aaf85;
background-color: #2d8968;
}
.btn-slack:not(:disabled):not(.disabled):active:focus,
.btn-slack:not(:disabled):not(.disabled).active:focus,
.show > .btn-slack.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(58, 175, 133, .5);
}
.btn-dribbble
{
color: #fff;
border-color: #ea4c89;
background-color: #ea4c89;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-dribbble:hover
{
color: #fff;
border-color: #ea4c89;
background-color: #ea4c89;
}
.btn-dribbble:focus,
.btn-dribbble.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(234, 76, 137, .5);
}
.btn-dribbble.disabled,
.btn-dribbble:disabled
{
color: #fff;
border-color: #ea4c89;
background-color: #ea4c89;
}
.btn-dribbble:not(:disabled):not(.disabled):active,
.btn-dribbble:not(:disabled):not(.disabled).active,
.show > .btn-dribbble.dropdown-toggle
{
color: #fff;
border-color: #ea4c89;
background-color: #e51e6b;
}
.btn-dribbble:not(:disabled):not(.disabled):active:focus,
.btn-dribbble:not(:disabled):not(.disabled).active:focus,
.show > .btn-dribbble.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(234, 76, 137, .5);
}
.btn-github
{
color: #fff;
border-color: #222;
background-color: #222;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.btn-github:hover
{
color: #fff;
border-color: #222;
background-color: #222;
}
.btn-github:focus,
.btn-github.focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08), 0 0 0 0 rgba(34, 34, 34, .5);
}
.btn-github.disabled,
.btn-github:disabled
{
color: #fff;
border-color: #222;
background-color: #222;
}
.btn-github:not(:disabled):not(.disabled):active,
.btn-github:not(:disabled):not(.disabled).active,
.show > .btn-github.dropdown-toggle
{
color: #fff;
border-color: #222;
background-color: #090909;
}
.btn-github:not(:disabled):not(.disabled):active:focus,
.btn-github:not(:disabled):not(.disabled).active:focus,
.show > .btn-github.dropdown-toggle:focus
{
box-shadow: none, 0 0 0 0 rgba(34, 34, 34, .5);
}
.card-translucent
{
background-color: rgba(18, 91, 152, .08);
}
.card-profile-image
{
position: relative;
}
.card-profile-image img
{
position: absolute;
left: 50%;
max-width: 180px;
transition: all .15s ease;
transform: translate(-50%, -30%);
border-radius: .375rem;
}
.card-profile-image img:hover
{
transform: translate(-50%, -33%);
}
.card-profile-stats
{
padding: 1rem 0;
}
.card-profile-stats > div
{
margin-right: 1rem;
padding: .875rem;
text-align: center;
}
.card-profile-stats > div:last-child
{
margin-right: 0;
}
.card-profile-stats > div .heading
{
font-size: 1.1rem;
font-weight: bold;
display: block;
}
.card-profile-stats > div .description
{
font-size: .875rem;
color: #adb5bd;
}
.card-profile-actions
{
padding: .875rem;
}
.card-blockquote
{
position: relative;
padding: 2rem;
}
.card-blockquote .svg-bg
{
position: absolute;
top: -94px;
left: 0;
display: block;
width: 100%;
height: 95px;
}
.card-lift--hover:hover
{
transition: all .15s ease;
transform: translateY(-20px);
}
@media screen and (prefers-reduced-motion: reduce)
{
.card-lift--hover:hover
{
transition: none;
}
}
.card-stats .card-body
{
padding: 1rem 1.5rem;
}
.card-stats .card-status-bullet
{
position: absolute;
top: 0;
right: 0;
transform: translate(50%, -50%);
}
.chart
{
position: relative;
height: 350px;
}
.chart-sm
{
height: 230px;
}
.chart-legend
{
font-size: .875rem;
display: flex;
margin-top: 2.5rem;
text-align: center;
color: #8898aa;
justify-content: center;
}
.chart-legend-item
{
display: inline-flex;
align-items: center;
}
.chart-legend-item + .chart-legend-item
{
margin-left: 1rem;
}
.chart-legend-indicator
{
display: inline-block;
width: .5rem;
height: .5rem;
margin-right: .375rem;
border-radius: 50%;
}
#chart-tooltip
{
z-index: 0;
}
#chart-tooltip .arrow
{
top: 100%;
left: 50%;
transform: translateX(-50%) translateX(-.5rem);
}
.chart-info-overlay
{
position: absolute;
z-index: 1;
top: 0;
left: 5%;
max-width: 350px;
padding: 20px;
}
.close
{
transition: all .15s ease;
}
.close > span:not(.sr-only)
{
font-size: 1.25rem;
line-height: 17px;
display: block;
width: 1.25rem;
height: 1.25rem;
transition: all .15s ease;
color: rgba(0, 0, 0, .6);
border-radius: 50%;
background-color: transparent;
}
.close:hover,
.close:focus
{
color: rgba(0, 0, 0, .9);
outline: none;
background-color: transparent;
}
.close:hover span:not(.sr-only),
.close:focus span:not(.sr-only)
{
background-color: transparent;
}
.main-content
{
position: relative;
}
.main-content .navbar-top
{
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
padding-right: 0 !important;
padding-left: 0 !important;
background-color: transparent;
}
@media (min-width: 768px)
{
.main-content .container-fluid
{
padding-right: 39px !important;
padding-left: 39px !important;
}
}
.navbar-vertical.navbar-expand-xs.fixed-left + .main-content
{
margin-left: 250px;
}
.navbar-vertical.navbar-expand-xs.fixed-right + .main-content
{
margin-right: 250px;
}
@media (min-width: 576px)
{
.navbar-vertical.navbar-expand-sm.fixed-left + .main-content
{
margin-left: 250px;
}
.navbar-vertical.navbar-expand-sm.fixed-right + .main-content
{
margin-right: 250px;
}
}
@media (min-width: 768px)
{
.navbar-vertical.navbar-expand-md.fixed-left + .main-content
{
margin-left: 250px;
}
.navbar-vertical.navbar-expand-md.fixed-right + .main-content
{
margin-right: 250px;
}
}
@media (min-width: 992px)
{
.navbar-vertical.navbar-expand-lg.fixed-left + .main-content
{
margin-left: 250px;
}
.navbar-vertical.navbar-expand-lg.fixed-right + .main-content
{
margin-right: 250px;
}
}
@media (min-width: 1200px)
{
.navbar-vertical.navbar-expand-xl.fixed-left + .main-content
{
margin-left: 250px;
}
.navbar-vertical.navbar-expand-xl.fixed-right + .main-content
{
margin-right: 250px;
}
}
.custom-checkbox .custom-control-input ~ .custom-control-label
{
font-size: .875rem;
cursor: pointer;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before
{
border-color: #5e72e4;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after
{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 8 8\'%3E%3Cpath fill=\'%23fff\' d=\'M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z\'/%3E%3C/svg%3E');
}
.custom-checkbox .custom-control-input:disabled ~ .custom-control-label::before
{
border-color: #e9ecef;
}
.custom-checkbox .custom-control-input:disabled:checked::before
{
border-color: rgba(94, 114, 228, .5);
}
.custom-control-label::before
{
transition: all .2s cubic-bezier(.68, -.55, .265, 1.55);
border: 1px solid #cad1d7;
}
.custom-control-label span
{
position: relative;
top: 2px;
}
.custom-control-label
{
margin-bottom: 0;
}
.custom-control-alternative .custom-control-label::before
{
border: 0;
box-shadow: 0 1px 3px rgba(50, 50, 93, .15), 0 1px 0 rgba(0, 0, 0, .02);
}
.custom-control-alternative .custom-control-input:checked ~ .custom-control-label::before
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.custom-control-alternative .custom-control-input:active ~ .custom-control-label::before,
.custom-control-alternative .custom-control-input:focus ~ .custom-control-label::before
{
box-shadow: 0 1px 3px rgba(50, 50, 93, .15), 0 1px 0 rgba(0, 0, 0, .02);
}
.custom-checkbox .custom-control-input ~ .custom-control-label
{
font-size: .875rem;
cursor: pointer;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before
{
border-color: #5e72e4;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after
{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 8 8\'%3E%3Cpath fill=\'%23fff\' d=\'M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z\'/%3E%3C/svg%3E');
}
.custom-checkbox .custom-control-input:disabled ~ .custom-control-label::before
{
border-color: #e9ecef;
}
.custom-checkbox .custom-control-input:disabled:checked::before
{
border-color: rgba(94, 114, 228, .5);
}
.custom-radio .custom-control-input ~ .custom-control-label
{
font-size: .875rem;
cursor: pointer;
}
.custom-radio .custom-control-input:checked ~ .custom-control-label::before
{
border-color: #5e72e4;
}
.custom-radio .custom-control-input:checked ~ .custom-control-label::after
{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'-4 -4 8 8\'%3E%3Ccircle r=\'3\' fill=\'%23fff\'/%3E%3C/svg%3E');
}
.custom-radio .custom-control-input:disabled ~ .custom-control-label::before
{
border-color: #e9ecef;
}
.custom-radio .custom-control-input:disabled:checked::before
{
border-color: rgba(94, 114, 228, .5);
}
.custom-toggle
{
position: relative;
display: inline-block;
width: 50px;
height: 1.5rem;
}
.custom-toggle input
{
display: none;
}
.custom-toggle input:checked + .custom-toggle-slider
{
border: 1px solid #007bff;
background: #007bff;
}
.custom-toggle input:checked + .custom-toggle-slider:before
{
transform: translateX(1.625rem);
background: #ffffff;
}
.custom-toggle input:disabled + .custom-toggle-slider
{
border: 1px solid #e9ecef;
}
.custom-toggle input:disabled:checked + .custom-toggle-slider
{
border: 1px solid #e9ecef;
}
.custom-toggle input:disabled:checked + .custom-toggle-slider:before
{
background-color: #8a98eb;
}
.custom-toggle-slider
{
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
cursor: pointer;
border: 1px solid #cad1d7;
border-radius: 34px !important;
background-color: transparent;
}
.custom-toggle-slider:before
{
position: absolute;
bottom: 2px;
left: 2px;
width: 18px;
height: 18px;
content: '';
transition: all .2s cubic-bezier(.68, -.55, .265, 1.55);
border-radius: 50% !important;
background-color: #e9ecef;
}
.dropdown,
.dropup,
.dropright,
.dropleft
{
display: inline-block;
}
.dropdown-menu
{
min-width: 12rem;
}
.dropdown-menu .dropdown-item
{
font-size: .875rem;
padding: .5rem 1rem;
}
.dropdown-menu .dropdown-item > i,
.dropdown-menu .dropdown-item > svg
{
font-size: 1rem;
margin-right: 1rem;
vertical-align: -17%;
}
.dropdown-header
{
font-size: .625rem;
font-weight: 700;
padding-right: 1rem;
padding-left: 1rem;
text-transform: uppercase;
color: #f6f9fc;
}
.dropdown-menu a.media > div:first-child
{
line-height: 1;
}
.dropdown-menu a.media p
{
color: #8898aa;
}
.dropdown-menu a.media:hover .heading,
.dropdown-menu a.media:hover p
{
color: #172b4d !important;
}
.dropdown-menu-sm
{
min-width: 100px;
border: .4375rem;
}
.dropdown-menu-lg
{
min-width: 260px;
border-radius: .4375rem;
}
.dropdown-menu-xl
{
min-width: 450px;
border-radius: .4375rem;
}
.footer
{
padding: 2.5rem 0;
background: #f7fafc;
}
.footer .col-footer .heading
{
font-size: .875rem;
font-weight: 600;
margin-bottom: 1rem;
letter-spacing: 0;
text-transform: uppercase;
color: #8898aa;
}
.footer .nav .nav-item .nav-link,
.footer .footer-link
{
color: #8898aa !important;
}
.footer .nav .nav-item .nav-link:hover,
.footer .footer-link:hover
{
color: #525f7f !important;
}
.footer .list-unstyled li a
{
font-size: .85rem;
display: inline-block;
padding: .125rem 0;
color: #8898aa;
}
.footer .list-unstyled li a:hover
{
color: #525f7f;
}
.footer .copyright
{
font-size: .875rem;
}
.footer-dark .col-footer .heading
{
color: #fff;
}
.nav-footer .nav-link
{
font-size: .875rem;
}
.nav-footer .nav-item:last-child .nav-link
{
padding-right: 0;
}
.footer.has-cards
{
position: relative;
overflow: hidden;
margin-top: -420px;
padding-top: 500px;
pointer-events: none;
background: transparent;
}
.footer.has-cards:before
{
position: absolute;
top: 600px;
right: 0;
left: 0;
height: 2000px;
content: '';
transform: skew(0, -8deg);
background: #f7fafc;
}
.footer.has-cards .container
{
position: relative;
pointer-events: auto;
}
.form-control-label
{
font-size: .875rem;
font-weight: 600;
color: #525f7f;
}
.form-control
{
font-size: .875rem;
}
.form-control:focus:-ms-input-placeholder
{
color: #adb5bd;
}
.form-control:focus::-ms-input-placeholder
{
color: #adb5bd;
}
.form-control:focus::placeholder
{
color: #adb5bd;
}
textarea[resize='none']
{
resize: none !important;
}
textarea[resize='both']
{
resize: both !important;
}
textarea[resize='vertical']
{
resize: vertical !important;
}
textarea[resize='horizontal']
{
resize: horizontal !important;
}
.form-control-muted
{
border-color: #f7fafe;
background-color: #f7fafe;
box-shadow: none;
}
.form-control-muted:focus
{
background-color: #fcfdff;
}
.form-control-alternative
{
transition: box-shadow .15s ease;
border: 0;
box-shadow: 0 1px 3px rgba(50, 50, 93, .15), 0 1px 0 rgba(0, 0, 0, .02);
}
.form-control-alternative:focus
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.form-control-lg
{
font-size: 1rem;
}
.has-success,
.has-danger
{
position: relative;
}
.has-success:after,
.has-danger:after
{
font-family: 'NucleoIcons';
font-size: 9px;
line-height: 19px;
position: absolute;
top: 2px;
right: 15px;
display: inline-block;
width: 19px;
height: 19px;
transform: translateY(50%);
text-align: center;
opacity: 1;
border-radius: 50%;
}
.has-success:after
{
content: '\ea26';
color: daken(#2dce89, 18%);
background-color: #69deac;
}
.has-success .form-control
{
background-color: #fff;
}
.has-success .form-control:focus
{
border-color: rgba(50, 151, 211, .25);
}
.has-success .form-control:-ms-input-placeholder
{
color: #2dce89;
}
.has-success .form-control::-ms-input-placeholder
{
color: #2dce89;
}
.has-success .form-control::placeholder
{
color: #2dce89;
}
.has-danger:after
{
content: '\ea53';
color: daken(#fb6340, 18%);
background-color: #fda08b;
}
.has-danger .form-control
{
background-color: #fff;
}
.has-danger .form-control:focus
{
border-color: rgba(50, 151, 211, .25);
}
.has-danger .form-control:-ms-input-placeholder
{
color: #fb6340;
}
.has-danger .form-control::-ms-input-placeholder
{
color: #fb6340;
}
.has-danger .form-control::placeholder
{
color: #fb6340;
}
.input-group
{
transition: all .15s ease;
border-radius: .375rem;
box-shadow: none;
}
.input-group .form-control
{
box-shadow: none;
}
.input-group .form-control:not(:first-child)
{
padding-left: 0;
border-left: 0;
}
.input-group .form-control:not(:last-child)
{
padding-right: 0;
border-right: 0;
}
.input-group .form-control:focus
{
box-shadow: none;
}
.input-group-text
{
transition: all .2s cubic-bezier(.68, -.55, .265, 1.55);
}
.input-group-alternative
{
transition: box-shadow .15s ease;
border: 0;
box-shadow: 0 1px 3px rgba(50, 50, 93, .15), 0 1px 0 rgba(0, 0, 0, .02);
}
.input-group-alternative .form-control,
.input-group-alternative .input-group-text
{
border: 0;
box-shadow: none;
}
.focused .input-group-alternative
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08) !important;
}
.focused .input-group
{
box-shadow: none;
}
.focused .input-group-text
{
color: #8898aa;
border-color: rgba(50, 151, 211, .25);
background-color: #fff;
}
.focused .form-control
{
border-color: rgba(50, 151, 211, .25);
}
.header
{
position: relative;
}
.icon
{
width: 3rem;
height: 3rem;
}
.icon i,
.icon svg
{
font-size: 2.25rem;
}
.icon + .icon-text
{
width: calc(100% - 3rem - 1);
padding-left: 1rem;
}
.icon-xl
{
width: 5rem;
height: 5rem;
}
.icon-xl i,
.icon-xl svg
{
font-size: 4.25rem;
}
.icon-xl + .icon-text
{
width: calc(100% - $icon-size-xl - 1);
}
.icon-lg
{
width: 4rem;
height: 4rem;
}
.icon-lg i,
.icon-lg svg
{
font-size: 3.25rem;
}
.icon-lg + .icon-text
{
width: calc(100% - $icon-size-lg - 1);
}
.icon-sm
{
width: 2rem;
height: 2rem;
}
.icon-sm i,
.icon-sm svg
{
font-size: 1.25rem;
}
.icon-sm + .icon-text
{
width: calc(100% - $icon-size-sm - 1);
}
.icon-shape
{
display: inline-flex;
padding: 12px;
text-align: center;
border-radius: 50%;
align-items: center;
justify-content: center;
}
.icon-shape i,
.icon-shape svg
{
font-size: 1.25rem;
}
.icon-shape.icon-lg i,
.icon-shape.icon-lg svg
{
font-size: 1.625rem;
}
.icon-shape.icon-sm i,
.icon-shape.icon-sm svg
{
font-size: .875rem;
}
.icon-shape svg
{
width: 30px;
height: 30px;
}
.icon-shape-primary
{
color: #2643e9;
background-color: rgba(138, 152, 235, .5);
}
.icon-shape-secondary
{
color: #cfe3f1;
background-color: rgba(255, 255, 255, .5);
}
.icon-shape-success
{
color: #1aae6f;
background-color: rgba(84, 218, 161, .5);
}
.icon-shape-info
{
color: #03acca;
background-color: rgba(65, 215, 242, .5);
}
.icon-shape-warning
{
color: #ff3709;
background-color: rgba(252, 140, 114, .5);
}
.icon-shape-danger
{
color: #f80031;
background-color: rgba(247, 103, 131, .5);
}
.icon-shape-light
{
color: #879cb0;
background-color: rgba(201, 207, 212, .5);
}
.icon-shape-dark
{
color: #090c0e;
background-color: rgba(56, 63, 69, .5);
}
.icon-shape-default
{
color: #091428;
background-color: rgba(35, 65, 116, .5);
}
.icon-shape-white
{
color: #e8e3e3;
background-color: rgba(255, 255, 255, .5);
}
.icon-shape-neutral
{
color: #e8e3e3;
background-color: rgba(255, 255, 255, .5);
}
.icon-shape-darker
{
color: black;
background-color: rgba(26, 26, 26, .5);
}
.input-group
{
transition: all .15s ease;
border-radius: .375rem;
box-shadow: none;
}
.input-group .form-control
{
box-shadow: none;
}
.input-group .form-control:not(:first-child)
{
padding-left: 0;
border-left: 0;
}
.input-group .form-control:not(:last-child)
{
padding-right: 0;
border-right: 0;
}
.input-group .form-control:focus
{
box-shadow: none;
}
.input-group-text
{
transition: all .2s cubic-bezier(.68, -.55, .265, 1.55);
}
.input-group-alternative
{
transition: box-shadow .15s ease;
border: 0;
box-shadow: 0 1px 3px rgba(50, 50, 93, .15), 0 1px 0 rgba(0, 0, 0, .02);
}
.input-group-alternative .form-control,
.input-group-alternative .input-group-text
{
border: 0;
box-shadow: none;
}
.focused .input-group-alternative
{
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08) !important;
}
.focused .input-group
{
box-shadow: none;
}
.focused .input-group-text
{
color: #8898aa;
border-color: rgba(50, 151, 211, .25);
background-color: #fff;
}
.focused .form-control
{
border-color: rgba(50, 151, 211, .25);
}
.list-group-space .list-group-item
{
margin-bottom: 1.5rem;
border-radius: .375rem;
}
.list-group-img
{
width: 3rem;
height: 3rem;
margin: -.1rem 1.2rem 0 -.2rem;
vertical-align: top;
border-radius: 50%;
}
.list-group-content
{
min-width: 0;
flex: 1 1;
}
.list-group-content > p
{
line-height: 1.5;
margin: .2rem 0 0;
color: #adb5bd;
}
.list-group-heading
{
font-size: 1rem;
color: #32325d;
}
.list-group-heading > small
{
font-weight: 500;
float: right;
color: #adb5bd;
}
.map-canvas
{
position: relative;
width: 100%;
height: 500px;
border-radius: .375rem;
}
.mask
{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: all .15s ease;
}
@media screen and (prefers-reduced-motion: reduce)
{
.mask
{
transition: none;
}
}
.modal-fluid .modal-dialog
{
margin-top: 0;
margin-bottom: 0;
}
.modal-fluid .modal-content
{
border-radius: 0;
}
.modal-primary .modal-title
{
color: #fff;
}
.modal-primary .modal-header,
.modal-primary .modal-footer
{
border-color: rgba(255, 255, 255, .075);
}
.modal-primary .modal-content
{
color: #fff;
background-color: #5e72e4;
}
.modal-primary .modal-content .heading
{
color: #fff;
}
.modal-primary .close > span:not(.sr-only)
{
color: #fff;
}
.modal-secondary .modal-title
{
color: #212529;
}
.modal-secondary .modal-header,
.modal-secondary .modal-footer
{
border-color: rgba(33, 37, 41, .075);
}
.modal-secondary .modal-content
{
color: #212529;
background-color: #f7fafc;
}
.modal-secondary .modal-content .heading
{
color: #212529;
}
.modal-secondary .close > span:not(.sr-only)
{
color: #fff;
}
.modal-success .modal-title
{
color: #fff;
}
.modal-success .modal-header,
.modal-success .modal-footer
{
border-color: rgba(255, 255, 255, .075);
}
.modal-success .modal-content
{
color: #fff;
background-color: #2dce89;
}
.modal-success .modal-content .heading
{
color: #fff;
}
.modal-success .close > span:not(.sr-only)
{
color: #fff;
}
.modal-info .modal-title
{
color: #fff;
}
.modal-info .modal-header,
.modal-info .modal-footer
{
border-color: rgba(255, 255, 255, .075);
}
.modal-info .modal-content
{
color: #fff;
background-color: #11cdef;
}
.modal-info .modal-content .heading
{
color: #fff;
}
.modal-info .close > span:not(.sr-only)
{
color: #fff;
}
.modal-warning .modal-title
{
color: #fff;
}
.modal-warning .modal-header,
.modal-warning .modal-footer
{
border-color: rgba(255, 255, 255, .075);
}
.modal-warning .modal-content
{
color: #fff;
background-color: #fb6340;
}
.modal-warning .modal-content .heading
{
color: #fff;
}
.modal-warning .close > span:not(.sr-only)
{
color: #fff;
}
.modal-danger .modal-title
{
color: #fff;
}
.modal-danger .modal-header,
.modal-danger .modal-footer
{
border-color: rgba(255, 255, 255, .075);
}
.modal-danger .modal-content
{
color: #fff;
background-color: #f5365c;
}
.modal-danger .modal-content .heading
{
color: #fff;
}
.modal-danger .close > span:not(.sr-only)
{
color: #fff;
}
.modal-light .modal-title
{
color: #fff;
}
.modal-light .modal-header,
.modal-light .modal-footer
{
border-color: rgba(255, 255, 255, .075);
}
.modal-light .modal-content
{
color: #fff;
background-color: #adb5bd;
}
.modal-light .modal-content .heading
{
color: #fff;
}
.modal-light .close > span:not(.sr-only)
{
color: #fff;
}
.modal-dark .modal-title
{
color: #fff;
}
.modal-dark .modal-header,
.modal-dark .modal-footer
{
border-color: rgba(255, 255, 255, .075);
}
.modal-dark .modal-content
{
color: #fff;
background-color: #212529;
}
.modal-dark .modal-content .heading
{
color: #fff;
}
.modal-dark .close > span:not(.sr-only)
{
color: #fff;
}
.modal-default .modal-title
{
color: #fff;
}
.modal-default .modal-header,
.modal-default .modal-footer
{
border-color: rgba(255, 255, 255, .075);
}
.modal-default .modal-content
{
color: #fff;
background-color: #172b4d;
}
.modal-default .modal-content .heading
{
color: #fff;
}
.modal-default .close > span:not(.sr-only)
{
color: #fff;
}
.modal-white .modal-title
{
color: #212529;
}
.modal-white .modal-header,
.modal-white .modal-footer
{
border-color: rgba(33, 37, 41, .075);
}
.modal-white .modal-content
{
color: #212529;
background-color: #fff;
}
.modal-white .modal-content .heading
{
color: #212529;
}
.modal-white .close > span:not(.sr-only)
{
color: #fff;
}
.modal-neutral .modal-title
{
color: #212529;
}
.modal-neutral .modal-header,
.modal-neutral .modal-footer
{
border-color: rgba(33, 37, 41, .075);
}
.modal-neutral .modal-content
{
color: #212529;
background-color: #fff;
}
.modal-neutral .modal-content .heading
{
color: #212529;
}
.modal-neutral .close > span:not(.sr-only)
{
color: #fff;
}
.modal-darker .modal-title
{
color: #fff;
}
.modal-darker .modal-header,
.modal-darker .modal-footer
{
border-color: rgba(255, 255, 255, .075);
}
.modal-darker .modal-content
{
color: #fff;
background-color: black;
}
.modal-darker .modal-content .heading
{
color: #fff;
}
.modal-darker .close > span:not(.sr-only)
{
color: #fff;
}
.nav-wrapper
{
padding: 1rem 0;
border-top-left-radius: .375rem;
border-top-right-radius: .375rem;
}
.nav-wrapper + .card
{
border-top-left-radius: 0;
border-top-right-radius: 0;
border-bottom-right-radius: .375rem;
border-bottom-left-radius: .375rem;
}
.nav-link
{
color: #525f7f;
}
.nav-link:hover
{
color: #5e72e4;
}
.nav-link i.ni
{
position: relative;
top: 2px;
}
.nav-pills .nav-item:not(:last-child)
{
padding-right: 1rem;
}
.nav-pills .nav-link
{
font-size: .875rem;
font-weight: 500;
padding: .75rem 1rem;
transition: all .15s ease;
color: #5e72e4;
background-color: #fff;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
}
.nav-pills .nav-link:hover
{
color: #485fe0;
}
.nav-pills .nav-link.active,
.nav-pills .show > .nav-link
{
color: #fff;
background-color: #5e72e4;
}
@media (max-width: 575.98px)
{
.nav-pills .nav-item
{
margin-bottom: 1rem;
}
}
@media (max-width: 767.98px)
{
.nav-pills:not(.nav-pills-circle) .nav-item
{
padding-right: 0;
}
}
.nav-pills-circle .nav-link
{
line-height: 60px;
width: 60px;
height: 60px;
padding: 0;
text-align: center;
border-radius: 50%;
}
.nav-pills-circle .nav-link-icon i,
.nav-pills-circle .nav-link-icon svg
{
font-size: 1rem;
}
.navbar-horizontal .navbar-nav .nav-link
{
font-size: .9rem;
font-weight: 400;
transition: all .15s linear;
letter-spacing: 0;
text-transform: normal;
}
@media screen and (prefers-reduced-motion: reduce)
{
.navbar-horizontal .navbar-nav .nav-link
{
transition: none;
}
}
.navbar-horizontal .navbar-nav .nav-link .nav-link-inner--text
{
margin-left: .25rem;
}
.navbar-horizontal .navbar-brand
{
font-size: .875rem;
font-size: .875rem;
font-weight: 600;
letter-spacing: .05px;
text-transform: uppercase;
}
.navbar-horizontal .navbar-brand img
{
height: 30px;
}
.navbar-horizontal .navbar-dark .navbar-brand
{
color: #fff;
}
.navbar-horizontal .navbar-light .navbar-brand
{
color: #32325d;
}
.navbar-horizontal .navbar-nav .nav-item .media:not(:last-child)
{
margin-bottom: 1.5rem;
}
@media (min-width: 992px)
{
.navbar-horizontal .navbar-nav .nav-item
{
margin-right: .5rem;
}
.navbar-horizontal .navbar-nav .nav-item [data-toggle='dropdown']::after
{
transition: all .15s ease;
}
.navbar-horizontal .navbar-nav .nav-item.show [data-toggle='dropdown']::after
{
transform: rotate(180deg);
}
.navbar-horizontal .navbar-nav .nav-link
{
padding-top: 1rem;
padding-bottom: 1rem;
border-radius: .375rem;
}
.navbar-horizontal .navbar-nav .nav-link i
{
margin-right: .625rem;
}
.navbar-horizontal .navbar-nav .nav-link-icon
{
font-size: 1rem;
padding-right: .5rem !important;
padding-left: .5rem !important;
border-radius: .375rem;
}
.navbar-horizontal .navbar-nav .nav-link-icon i
{
margin-right: 0;
}
}
.navbar-horizontal .navbar-transparent
{
position: absolute;
z-index: 100;
top: 0;
width: 100%;
border: 0;
background-color: transparent;
box-shadow: none;
}
.navbar-horizontal .navbar-transparent .navbar-brand
{
color: white;
}
.navbar-horizontal .navbar-transparent .navbar-toggler
{
color: white;
}
.navbar-horizontal .navbar-transparent .navbar-toggler-icon
{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg viewBox=\'0 0 30 30\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cpath stroke=\'rgba(255, 255, 255, 0.95)\' stroke-width=\'2\' stroke-linecap=\'round\' stroke-miterlimit=\'10\' d=\'M4 7h22M4 15h22M4 23h22\'/%3E%3C/svg%3E');
}
@media (min-width: 768px)
{
.navbar-horizontal .navbar-transparent .navbar-nav .nav-link
{
color: rgba(255, 255, 255, .95);
}
.navbar-horizontal .navbar-transparent .navbar-nav .nav-link:hover,
.navbar-horizontal .navbar-transparent .navbar-nav .nav-link:focus
{
color: rgba(255, 255, 255, .65);
}
.navbar-horizontal .navbar-transparent .navbar-nav .nav-link.disabled
{
color: rgba(255, 255, 255, .25);
}
.navbar-horizontal .navbar-transparent .navbar-nav .show > .nav-link,
.navbar-horizontal .navbar-transparent .navbar-nav .active > .nav-link,
.navbar-horizontal .navbar-transparent .navbar-nav .nav-link.show,
.navbar-horizontal .navbar-transparent .navbar-nav .nav-link.active
{
color: rgba(255, 255, 255, .65);
}
.navbar-horizontal .navbar-transparent .navbar-brand
{
color: rgba(255, 255, 255, .95);
}
.navbar-horizontal .navbar-transparent .navbar-brand:hover,
.navbar-horizontal .navbar-transparent .navbar-brand:focus
{
color: rgba(255, 255, 255, .95);
}
}
.navbar-vertical
{
box-shadow: 0 0 2rem 0 rgba(136, 152, 170, .15) !important;
}
.navbar-vertical .navbar
{
border-width: 0 0 1px 0;
border-style: solid;
}
.navbar-vertical .navbar-light
{
border-color: #f6f9fc;
background-color: transparent;
}
.navbar-vertical .navbar-brand
{
margin-right: 0;
}
.navbar-vertical .navbar-brand-img,
.navbar-vertical .navbar-brand > img
{
max-width: 100%;
max-height: 2rem;
}
@media (min-width: 768px)
{
.navbar-vertical .navbar-collapse
{
margin-right: -1rem;
margin-left: -1rem;
padding-right: 1rem;
padding-left: 1rem;
}
.navbar-vertical .navbar-collapse:before
{
display: block;
margin: 1rem -1rem;
content: '';
}
}
.navbar-vertical .navbar-nav
{
margin-right: -1rem;
margin-left: -1rem;
}
.navbar-vertical .navbar-nav .nav-link
{
font-size: .9rem;
padding-right: 1rem;
padding-left: 1rem;
}
.navbar-vertical .navbar-nav .nav-link.active
{
position: relative;
}
.navbar-vertical .navbar-nav .nav-link.active:before
{
position: absolute;
top: .25rem;
bottom: .25rem;
left: 0;
content: '';
border-left: 2px solid #5e72e4;
}
.navbar-vertical .navbar-nav .nav-link > i
{
font-size: .9375rem;
line-height: 1.5rem;
min-width: 2.25rem;
}
.navbar-vertical .navbar-nav .nav-link .dropdown-menu
{
border: none;
}
.navbar-vertical .navbar-nav .nav-link .dropdown-menu .dropdown-menu
{
margin-left: .75rem;
}
.navbar-vertical .navbar-nav .nav-link
{
display: flex;
align-items: center;
}
.navbar-vertical .navbar-nav .nav-link[data-toggle='collapse']:after
{
font-family: 'Font Awesome 5 Free';
font-weight: 700;
font-style: normal;
font-variant: normal;
display: inline-block;
margin-left: auto;
content: '\f105';
transition: all .15s ease;
color: #8898aa;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
}
.navbar-vertical .navbar-nav .nav-link[data-toggle='collapse'][aria-expanded='true']:after
{
transform: rotate(90deg);
}
.navbar-vertical .navbar-nav .nav .nav-link
{
padding-left: 3.25rem;
}
.navbar-vertical .navbar-nav .nav .nav .nav-link
{
padding-left: 3.75rem;
}
.navbar-vertical .navbar-heading
{
font-size: .75rem;
padding-top: .25rem;
padding-bottom: .25rem;
letter-spacing: .04em;
text-transform: uppercase;
}
.navbar-vertical.navbar-expand-xs
{
position: fixed;
top: 0;
bottom: 0;
display: block;
overflow-y: auto;
width: 100%;
max-width: 250px;
padding-right: 1.5rem;
padding-left: 1.5rem;
}
.navbar-vertical.navbar-expand-xs > [class*='container']
{
flex-direction: column;
min-height: 100%;
padding-right: 0;
padding-left: 0;
align-items: stretch;
}
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active)
{
.navbar-vertical.navbar-expand-xs > [class*='container']
{
height: 100%;
min-height: none;
}
}
.navbar-vertical.navbar-expand-xs.fixed-left
{
left: 0;
border-width: 0 1px 0 0;
}
.navbar-vertical.navbar-expand-xs.fixed-right
{
right: 0;
border-width: 0 0 0 1px;
}
.navbar-vertical.navbar-expand-xs .navbar-collapse
{
display: flex;
flex-direction: column;
margin-right: -1.5rem;
margin-left: -1.5rem;
padding-right: 1.5rem;
padding-left: 1.5rem;
flex: 1 1;
align-items: stretch;
}
.navbar-vertical.navbar-expand-xs .navbar-collapse > *
{
min-width: 100%;
}
.navbar-vertical.navbar-expand-xs .navbar-nav
{
flex-direction: column;
margin-right: -1.5rem;
margin-left: -1.5rem;
}
.navbar-vertical.navbar-expand-xs .navbar-nav .nav-link
{
padding: .65rem 1.5rem;
}
.navbar-vertical.navbar-expand-xs .navbar-nav .nav-link.active:before
{
top: .25rem;
right: auto;
bottom: .25rem;
left: 0;
border-bottom: 0;
border-left: 2px solid #5e72e4;
}
.navbar-vertical.navbar-expand-xs .navbar-nav .nav .nav-link
{
padding-left: 3.75rem;
}
.navbar-vertical.navbar-expand-xs .navbar-nav .nav .nav .nav-link
{
padding-left: 4.5rem;
}
.navbar-vertical.navbar-expand-xs .navbar-brand
{
display: block;
padding-top: 1rem;
padding-bottom: 1rem;
text-align: center;
}
.navbar-vertical.navbar-expand-xs .navbar-brand-img
{
max-height: 2.5rem;
}
.navbar-vertical.navbar-expand-xs .navbar-user
{
margin-right: -1.5rem;
margin-left: -1.5rem;
padding-top: 1rem;
padding-right: 1.5rem;
padding-bottom: 0rem;
padding-left: 1.5rem;
border-top: 1px solid #e9ecef;
}
.navbar-vertical.navbar-expand-xs .navbar-user .dropup .dropdown-menu
{
left: 50%;
transform: translateX(-50%);
}
@media (min-width: 576px)
{
.navbar-vertical.navbar-expand-sm
{
position: fixed;
top: 0;
bottom: 0;
display: block;
overflow-y: auto;
width: 100%;
max-width: 250px;
padding-right: 1.5rem;
padding-left: 1.5rem;
}
.navbar-vertical.navbar-expand-sm > [class*='container']
{
flex-direction: column;
min-height: 100%;
padding-right: 0;
padding-left: 0;
align-items: stretch;
}
}
@media all and (min-width: 576px) and (-ms-high-contrast: none), (min-width: 576px) and (-ms-high-contrast: active)
{
.navbar-vertical.navbar-expand-sm > [class*='container']
{
height: 100%;
min-height: none;
}
}
@media (min-width: 576px)
{
.navbar-vertical.navbar-expand-sm.fixed-left
{
left: 0;
border-width: 0 1px 0 0;
}
.navbar-vertical.navbar-expand-sm.fixed-right
{
right: 0;
border-width: 0 0 0 1px;
}
.navbar-vertical.navbar-expand-sm .navbar-collapse
{
display: flex;
flex-direction: column;
margin-right: -1.5rem;
margin-left: -1.5rem;
padding-right: 1.5rem;
padding-left: 1.5rem;
flex: 1 1;
align-items: stretch;
}
.navbar-vertical.navbar-expand-sm .navbar-collapse > *
{
min-width: 100%;
}
.navbar-vertical.navbar-expand-sm .navbar-nav
{
flex-direction: column;
margin-right: -1.5rem;
margin-left: -1.5rem;
}
.navbar-vertical.navbar-expand-sm .navbar-nav .nav-link
{
padding: .65rem 1.5rem;
}
.navbar-vertical.navbar-expand-sm .navbar-nav .nav-link.active:before
{
top: .25rem;
right: auto;
bottom: .25rem;
left: 0;
border-bottom: 0;
border-left: 2px solid #5e72e4;
}
.navbar-vertical.navbar-expand-sm .navbar-nav .nav .nav-link
{
padding-left: 3.75rem;
}
.navbar-vertical.navbar-expand-sm .navbar-nav .nav .nav .nav-link
{
padding-left: 4.5rem;
}
.navbar-vertical.navbar-expand-sm .navbar-brand
{
display: block;
padding-top: 1rem;
padding-bottom: 1rem;
text-align: center;
}
.navbar-vertical.navbar-expand-sm .navbar-brand-img
{
max-height: 2.5rem;
}
.navbar-vertical.navbar-expand-sm .navbar-user
{
margin-right: -1.5rem;
margin-left: -1.5rem;
padding-top: 1rem;
padding-right: 1.5rem;
padding-bottom: 0rem;
padding-left: 1.5rem;
border-top: 1px solid #e9ecef;
}
.navbar-vertical.navbar-expand-sm .navbar-user .dropup .dropdown-menu
{
left: 50%;
transform: translateX(-50%);
}
}
@media (min-width: 768px)
{
.navbar-vertical.navbar-expand-md
{
position: fixed;
top: 0;
bottom: 0;
display: block;
overflow-y: auto;
width: 100%;
max-width: 250px;
padding-right: 1.5rem;
padding-left: 1.5rem;
}
.navbar-vertical.navbar-expand-md > [class*='container']
{
flex-direction: column;
min-height: 100%;
padding-right: 0;
padding-left: 0;
align-items: stretch;
}
}
@media all and (min-width: 768px) and (-ms-high-contrast: none), (min-width: 768px) and (-ms-high-contrast: active)
{
.navbar-vertical.navbar-expand-md > [class*='container']
{
height: 100%;
min-height: none;
}
}
@media (min-width: 768px)
{
.navbar-vertical.navbar-expand-md.fixed-left
{
left: 0;
border-width: 0 1px 0 0;
}
.navbar-vertical.navbar-expand-md.fixed-right
{
right: 0;
border-width: 0 0 0 1px;
}
.navbar-vertical.navbar-expand-md .navbar-collapse
{
display: flex;
flex-direction: column;
margin-right: -1.5rem;
margin-left: -1.5rem;
padding-right: 1.5rem;
padding-left: 1.5rem;
flex: 1 1;
align-items: stretch;
}
.navbar-vertical.navbar-expand-md .navbar-collapse > *
{
min-width: 100%;
}
.navbar-vertical.navbar-expand-md .navbar-nav
{
flex-direction: column;
margin-right: -1.5rem;
margin-left: -1.5rem;
}
.navbar-vertical.navbar-expand-md .navbar-nav .nav-link
{
padding: .65rem 1.5rem;
}
.navbar-vertical.navbar-expand-md .navbar-nav .nav-link.active:before
{
top: .25rem;
right: auto;
bottom: .25rem;
left: 0;
border-bottom: 0;
border-left: 2px solid #5e72e4;
}
.navbar-vertical.navbar-expand-md .navbar-nav .nav .nav-link
{
padding-left: 3.75rem;
}
.navbar-vertical.navbar-expand-md .navbar-nav .nav .nav .nav-link
{
padding-left: 4.5rem;
}
.navbar-vertical.navbar-expand-md .navbar-brand
{
display: block;
padding-top: 1rem;
padding-bottom: 1rem;
text-align: center;
}
.navbar-vertical.navbar-expand-md .navbar-brand-img
{
max-height: 2.5rem;
}
.navbar-vertical.navbar-expand-md .navbar-user
{
margin-right: -1.5rem;
margin-left: -1.5rem;
padding-top: 1rem;
padding-right: 1.5rem;
padding-bottom: 0rem;
padding-left: 1.5rem;
border-top: 1px solid #e9ecef;
}
.navbar-vertical.navbar-expand-md .navbar-user .dropup .dropdown-menu
{
left: 50%;
transform: translateX(-50%);
}
}
@media (min-width: 992px)
{
.navbar-vertical.navbar-expand-lg
{
position: fixed;
top: 0;
bottom: 0;
display: block;
overflow-y: auto;
width: 100%;
max-width: 250px;
padding-right: 1.5rem;
padding-left: 1.5rem;
}
.navbar-vertical.navbar-expand-lg > [class*='container']
{
flex-direction: column;
min-height: 100%;
padding-right: 0;
padding-left: 0;
align-items: stretch;
}
}
@media all and (min-width: 992px) and (-ms-high-contrast: none), (min-width: 992px) and (-ms-high-contrast: active)
{
.navbar-vertical.navbar-expand-lg > [class*='container']
{
height: 100%;
min-height: none;
}
}
@media (min-width: 992px)
{
.navbar-vertical.navbar-expand-lg.fixed-left
{
left: 0;
border-width: 0 1px 0 0;
}
.navbar-vertical.navbar-expand-lg.fixed-right
{
right: 0;
border-width: 0 0 0 1px;
}
.navbar-vertical.navbar-expand-lg .navbar-collapse
{
display: flex;
flex-direction: column;
margin-right: -1.5rem;
margin-left: -1.5rem;
padding-right: 1.5rem;
padding-left: 1.5rem;
flex: 1 1;
align-items: stretch;
}
.navbar-vertical.navbar-expand-lg .navbar-collapse > *
{
min-width: 100%;
}
.navbar-vertical.navbar-expand-lg .navbar-nav
{
flex-direction: column;
margin-right: -1.5rem;
margin-left: -1.5rem;
}
.navbar-vertical.navbar-expand-lg .navbar-nav .nav-link
{
padding: .65rem 1.5rem;
}
.navbar-vertical.navbar-expand-lg .navbar-nav .nav-link.active:before
{
top: .25rem;
right: auto;
bottom: .25rem;
left: 0;
border-bottom: 0;
border-left: 2px solid #5e72e4;
}
.navbar-vertical.navbar-expand-lg .navbar-nav .nav .nav-link
{
padding-left: 3.75rem;
}
.navbar-vertical.navbar-expand-lg .navbar-nav .nav .nav .nav-link
{
padding-left: 4.5rem;
}
.navbar-vertical.navbar-expand-lg .navbar-brand
{
display: block;
padding-top: 1rem;
padding-bottom: 1rem;
text-align: center;
}
.navbar-vertical.navbar-expand-lg .navbar-brand-img
{
max-height: 2.5rem;
}
.navbar-vertical.navbar-expand-lg .navbar-user
{
margin-right: -1.5rem;
margin-left: -1.5rem;
padding-top: 1rem;
padding-right: 1.5rem;
padding-bottom: 0rem;
padding-left: 1.5rem;
border-top: 1px solid #e9ecef;
}
.navbar-vertical.navbar-expand-lg .navbar-user .dropup .dropdown-menu
{
left: 50%;
transform: translateX(-50%);
}
}
@media (min-width: 1200px)
{
.navbar-vertical.navbar-expand-xl
{
position: fixed;
top: 0;
bottom: 0;
display: block;
overflow-y: auto;
width: 100%;
max-width: 250px;
padding-right: 1.5rem;
padding-left: 1.5rem;
}
.navbar-vertical.navbar-expand-xl > [class*='container']
{
flex-direction: column;
min-height: 100%;
padding-right: 0;
padding-left: 0;
align-items: stretch;
}
}
@media all and (min-width: 1200px) and (-ms-high-contrast: none), (min-width: 1200px) and (-ms-high-contrast: active)
{
.navbar-vertical.navbar-expand-xl > [class*='container']
{
height: 100%;
min-height: none;
}
}
@media (min-width: 1200px)
{
.navbar-vertical.navbar-expand-xl.fixed-left
{
left: 0;
border-width: 0 1px 0 0;
}
.navbar-vertical.navbar-expand-xl.fixed-right
{
right: 0;
border-width: 0 0 0 1px;
}
.navbar-vertical.navbar-expand-xl .navbar-collapse
{
display: flex;
flex-direction: column;
margin-right: -1.5rem;
margin-left: -1.5rem;
padding-right: 1.5rem;
padding-left: 1.5rem;
flex: 1 1;
align-items: stretch;
}
.navbar-vertical.navbar-expand-xl .navbar-collapse > *
{
min-width: 100%;
}
.navbar-vertical.navbar-expand-xl .navbar-nav
{
flex-direction: column;
margin-right: -1.5rem;
margin-left: -1.5rem;
}
.navbar-vertical.navbar-expand-xl .navbar-nav .nav-link
{
padding: .65rem 1.5rem;
}
.navbar-vertical.navbar-expand-xl .navbar-nav .nav-link.active:before
{
top: .25rem;
right: auto;
bottom: .25rem;
left: 0;
border-bottom: 0;
border-left: 2px solid #5e72e4;
}
.navbar-vertical.navbar-expand-xl .navbar-nav .nav .nav-link
{
padding-left: 3.75rem;
}
.navbar-vertical.navbar-expand-xl .navbar-nav .nav .nav .nav-link
{
padding-left: 4.5rem;
}
.navbar-vertical.navbar-expand-xl .navbar-brand
{
display: block;
padding-top: 1rem;
padding-bottom: 1rem;
text-align: center;
}
.navbar-vertical.navbar-expand-xl .navbar-brand-img
{
max-height: 2.5rem;
}
.navbar-vertical.navbar-expand-xl .navbar-user
{
margin-right: -1.5rem;
margin-left: -1.5rem;
padding-top: 1rem;
padding-right: 1.5rem;
padding-bottom: 0rem;
padding-left: 1.5rem;
border-top: 1px solid #e9ecef;
}
.navbar-vertical.navbar-expand-xl .navbar-user .dropup .dropdown-menu
{
left: 50%;
transform: translateX(-50%);
}
}
.navbar-search .input-group
{
border: 2px solid;
border-radius: 2rem;
background-color: transparent;
}
.navbar-search .input-group .input-group-text
{
padding-left: 1rem;
background-color: transparent;
}
.navbar-search .form-control
{
width: 270px;
background-color: transparent;
}
.navbar-search-dark .input-group
{
border-color: rgba(255, 255, 255, .6);
}
.navbar-search-dark .input-group-text
{
color: rgba(255, 255, 255, .6);
}
.navbar-search-dark .form-control
{
color: rgba(255, 255, 255, .9);
}
.navbar-search-dark .form-control:-ms-input-placeholder
{
color: rgba(255, 255, 255, .6);
}
.navbar-search-dark .form-control::-ms-input-placeholder
{
color: rgba(255, 255, 255, .6);
}
.navbar-search-dark .form-control::placeholder
{
color: rgba(255, 255, 255, .6);
}
.navbar-search-dark .focused .input-group
{
border-color: rgba(255, 255, 255, .9);
}
.navbar-search-light .input-group
{
border-color: rgba(0, 0, 0, .6);
}
.navbar-search-light .input-group-text
{
color: rgba(0, 0, 0, .6);
}
.navbar-search-light .form-control
{
color: rgba(0, 0, 0, .9);
}
.navbar-search-light .form-control:-ms-input-placeholder
{
color: rgba(0, 0, 0, .6);
}
.navbar-search-light .form-control::-ms-input-placeholder
{
color: rgba(0, 0, 0, .6);
}
.navbar-search-light .form-control::placeholder
{
color: rgba(0, 0, 0, .6);
}
.navbar-search-light .focused .input-group
{
border-color: rgba(0, 0, 0, .9);
}
@media (min-width: 768px)
{
.navbar .dropdown-menu
{
margin: 0;
pointer-events: none;
opacity: 0;
}
.navbar .dropdown-menu-arrow:before
{
position: absolute;
z-index: -5;
bottom: 100%;
left: 20px;
display: block;
width: 12px;
height: 12px;
content: '';
transform: rotate(-45deg) translateY(12px);
border-radius: 2px;
background: #fff;
box-shadow: none;
}
.navbar .dropdown-menu-right:before
{
right: 20px;
left: auto;
}
.navbar:not(.navbar-nav-hover) .dropdown-menu.show
{
animation: show-navbar-dropdown .25s ease forwards;
pointer-events: auto;
opacity: 1;
}
.navbar:not(.navbar-nav-hover) .dropdown-menu.close
{
display: block;
animation: hide-navbar-dropdown .15s ease backwards;
}
.navbar.navbar-nav-hover .dropdown-menu
{
display: block;
transition: visibility .25s, opacity .25s, transform .25s;
transform: translate(0, 10px) perspective(200px) rotateX(-2deg);
pointer-events: none;
opacity: 0;
}
.navbar.navbar-nav-hover .nav-item.dropdown:hover > .dropdown-menu
{
display: block;
visibility: visible;
transform: translate(0, 0);
animation: none;
pointer-events: auto;
opacity: 1;
}
.navbar .dropdown-menu-inner
{
position: relative;
padding: 1rem;
}
@keyframes show-navbar-dropdown
{
0%
{
transition: visibility .25s, opacity .25s, transform .25s;
transform: translate(0, 10px) perspective(200px) rotateX(-2deg);
opacity: 0;
}
100%
{
transform: translate(0, 0);
opacity: 1;
}
}
@keyframes hide-navbar-dropdown
{
from
{
opacity: 1;
}
to
{
transform: translate(0, 10px);
opacity: 0;
}
}
}
.navbar-collapse-header
{
display: none;
}
@media (max-width: 767.98px)
{
.navbar-nav .nav-link
{
padding: .625rem 0;
color: #172b4d !important;
}
.navbar-nav .dropdown-menu
{
min-width: auto;
box-shadow: none;
}
.navbar-nav .dropdown-menu .media svg
{
width: 30px;
}
.navbar-collapse
{
position: absolute;
z-index: 1050;
top: 0;
right: 0;
left: 0;
overflow-y: auto;
width: calc(100% - 1.4rem);
height: auto !important;
margin: .7rem;
opacity: 0;
}
.navbar-collapse .navbar-toggler
{
position: relative;
display: inline-block;
width: 20px;
height: 20px;
padding: 0;
cursor: pointer;
}
.navbar-collapse .navbar-toggler span
{
position: absolute;
display: block;
width: 100%;
height: 2px;
opacity: 1;
border-radius: 2px;
background: #283448;
}
.navbar-collapse .navbar-toggler :nth-child(1)
{
transform: rotate(135deg);
}
.navbar-collapse .navbar-toggler :nth-child(2)
{
transform: rotate(-135deg);
}
.navbar-collapse .navbar-collapse-header
{
display: block;
margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(0, 0, 0, .1);
}
.navbar-collapse .collapse-brand img
{
height: 36px;
}
.navbar-collapse .collapse-close
{
text-align: right;
}
.navbar-collapse.collapsing,
.navbar-collapse.show
{
padding: 1.5rem;
animation: show-navbar-collapse .2s ease forwards;
border-radius: .375rem;
background: #fff;
box-shadow: 0 50px 100px rgba(50, 50, 93, .1), 0 15px 35px rgba(50, 50, 93, .15), 0 5px 15px rgba(0, 0, 0, .1);
}
.navbar-collapse.collapsing-out
{
animation: hide-navbar-collapse .2s ease forwards;
}
}
@keyframes show-navbar-collapse
{
0%
{
transform: scale(.95);
transform-origin: 100% 0;
opacity: 0;
}
100%
{
transform: scale(1);
opacity: 1;
}
}
@keyframes hide-navbar-collapse
{
from
{
transform: scale(1);
transform-origin: 100% 0;
opacity: 1;
}
to
{
transform: scale(.95);
opacity: 0;
}
}
.page-item.active .page-link
{
box-shadow: 0 7px 14px rgba(50, 50, 93, .1), 0 3px 6px rgba(0, 0, 0, .08);
}
.page-item .page-link,
.page-item span
{
font-size: .875rem;
display: flex;
width: 36px;
height: 36px;
margin: 0 3px;
padding: 0;
border-radius: 50% !important;
align-items: center;
justify-content: center;
}
.pagination-lg .page-item .page-link,
.pagination-lg .page-item span
{
line-height: 46px;
width: 46px;
height: 46px;
}
.pagination-sm .page-item .page-link,
.pagination-sm .page-item span
{
line-height: 30px;
width: 30px;
height: 30px;
}
.popover
{
border: 0;
}
.popover-header
{
font-weight: 600;
}
.popover-primary
{
background-color: #5e72e4;
}
.popover-primary .popover-header
{
color: #fff;
background-color: #5e72e4;
}
.popover-primary .popover-body
{
color: #fff;
}
.popover-primary .popover-header
{
border-color: rgba(255, 255, 255, .2);
}
.popover-primary.bs-popover-top .arrow::after,
.popover-primary.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: #5e72e4;
}
.popover-primary.bs-popover-right .arrow::after,
.popover-primary.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: #5e72e4;
}
.popover-primary.bs-popover-bottom .arrow::after,
.popover-primary.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: #5e72e4;
}
.popover-primary.bs-popover-left .arrow::after,
.popover-primary.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: #5e72e4;
}
.popover-secondary
{
background-color: #f7fafc;
}
.popover-secondary .popover-header
{
color: #212529;
background-color: #f7fafc;
}
.popover-secondary .popover-body
{
color: #212529;
}
.popover-secondary .popover-header
{
border-color: rgba(33, 37, 41, .2);
}
.popover-secondary.bs-popover-top .arrow::after,
.popover-secondary.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: #f7fafc;
}
.popover-secondary.bs-popover-right .arrow::after,
.popover-secondary.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: #f7fafc;
}
.popover-secondary.bs-popover-bottom .arrow::after,
.popover-secondary.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: #f7fafc;
}
.popover-secondary.bs-popover-left .arrow::after,
.popover-secondary.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: #f7fafc;
}
.popover-success
{
background-color: #2dce89;
}
.popover-success .popover-header
{
color: #fff;
background-color: #2dce89;
}
.popover-success .popover-body
{
color: #fff;
}
.popover-success .popover-header
{
border-color: rgba(255, 255, 255, .2);
}
.popover-success.bs-popover-top .arrow::after,
.popover-success.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: #2dce89;
}
.popover-success.bs-popover-right .arrow::after,
.popover-success.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: #2dce89;
}
.popover-success.bs-popover-bottom .arrow::after,
.popover-success.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: #2dce89;
}
.popover-success.bs-popover-left .arrow::after,
.popover-success.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: #2dce89;
}
.popover-info
{
background-color: #11cdef;
}
.popover-info .popover-header
{
color: #fff;
background-color: #11cdef;
}
.popover-info .popover-body
{
color: #fff;
}
.popover-info .popover-header
{
border-color: rgba(255, 255, 255, .2);
}
.popover-info.bs-popover-top .arrow::after,
.popover-info.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: #11cdef;
}
.popover-info.bs-popover-right .arrow::after,
.popover-info.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: #11cdef;
}
.popover-info.bs-popover-bottom .arrow::after,
.popover-info.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: #11cdef;
}
.popover-info.bs-popover-left .arrow::after,
.popover-info.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: #11cdef;
}
.popover-warning
{
background-color: #fb6340;
}
.popover-warning .popover-header
{
color: #fff;
background-color: #fb6340;
}
.popover-warning .popover-body
{
color: #fff;
}
.popover-warning .popover-header
{
border-color: rgba(255, 255, 255, .2);
}
.popover-warning.bs-popover-top .arrow::after,
.popover-warning.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: #fb6340;
}
.popover-warning.bs-popover-right .arrow::after,
.popover-warning.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: #fb6340;
}
.popover-warning.bs-popover-bottom .arrow::after,
.popover-warning.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: #fb6340;
}
.popover-warning.bs-popover-left .arrow::after,
.popover-warning.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: #fb6340;
}
.popover-danger
{
background-color: #f5365c;
}
.popover-danger .popover-header
{
color: #fff;
background-color: #f5365c;
}
.popover-danger .popover-body
{
color: #fff;
}
.popover-danger .popover-header
{
border-color: rgba(255, 255, 255, .2);
}
.popover-danger.bs-popover-top .arrow::after,
.popover-danger.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: #f5365c;
}
.popover-danger.bs-popover-right .arrow::after,
.popover-danger.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: #f5365c;
}
.popover-danger.bs-popover-bottom .arrow::after,
.popover-danger.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: #f5365c;
}
.popover-danger.bs-popover-left .arrow::after,
.popover-danger.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: #f5365c;
}
.popover-light
{
background-color: #adb5bd;
}
.popover-light .popover-header
{
color: #fff;
background-color: #adb5bd;
}
.popover-light .popover-body
{
color: #fff;
}
.popover-light .popover-header
{
border-color: rgba(255, 255, 255, .2);
}
.popover-light.bs-popover-top .arrow::after,
.popover-light.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: #adb5bd;
}
.popover-light.bs-popover-right .arrow::after,
.popover-light.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: #adb5bd;
}
.popover-light.bs-popover-bottom .arrow::after,
.popover-light.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: #adb5bd;
}
.popover-light.bs-popover-left .arrow::after,
.popover-light.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: #adb5bd;
}
.popover-dark
{
background-color: #212529;
}
.popover-dark .popover-header
{
color: #fff;
background-color: #212529;
}
.popover-dark .popover-body
{
color: #fff;
}
.popover-dark .popover-header
{
border-color: rgba(255, 255, 255, .2);
}
.popover-dark.bs-popover-top .arrow::after,
.popover-dark.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: #212529;
}
.popover-dark.bs-popover-right .arrow::after,
.popover-dark.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: #212529;
}
.popover-dark.bs-popover-bottom .arrow::after,
.popover-dark.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: #212529;
}
.popover-dark.bs-popover-left .arrow::after,
.popover-dark.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: #212529;
}
.popover-default
{
background-color: #172b4d;
}
.popover-default .popover-header
{
color: #fff;
background-color: #172b4d;
}
.popover-default .popover-body
{
color: #fff;
}
.popover-default .popover-header
{
border-color: rgba(255, 255, 255, .2);
}
.popover-default.bs-popover-top .arrow::after,
.popover-default.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: #172b4d;
}
.popover-default.bs-popover-right .arrow::after,
.popover-default.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: #172b4d;
}
.popover-default.bs-popover-bottom .arrow::after,
.popover-default.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: #172b4d;
}
.popover-default.bs-popover-left .arrow::after,
.popover-default.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: #172b4d;
}
.popover-white
{
background-color: #fff;
}
.popover-white .popover-header
{
color: #212529;
background-color: #fff;
}
.popover-white .popover-body
{
color: #212529;
}
.popover-white .popover-header
{
border-color: rgba(33, 37, 41, .2);
}
.popover-white.bs-popover-top .arrow::after,
.popover-white.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: #fff;
}
.popover-white.bs-popover-right .arrow::after,
.popover-white.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: #fff;
}
.popover-white.bs-popover-bottom .arrow::after,
.popover-white.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: #fff;
}
.popover-white.bs-popover-left .arrow::after,
.popover-white.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: #fff;
}
.popover-neutral
{
background-color: #fff;
}
.popover-neutral .popover-header
{
color: #212529;
background-color: #fff;
}
.popover-neutral .popover-body
{
color: #212529;
}
.popover-neutral .popover-header
{
border-color: rgba(33, 37, 41, .2);
}
.popover-neutral.bs-popover-top .arrow::after,
.popover-neutral.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: #fff;
}
.popover-neutral.bs-popover-right .arrow::after,
.popover-neutral.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: #fff;
}
.popover-neutral.bs-popover-bottom .arrow::after,
.popover-neutral.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: #fff;
}
.popover-neutral.bs-popover-left .arrow::after,
.popover-neutral.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: #fff;
}
.popover-darker
{
background-color: black;
}
.popover-darker .popover-header
{
color: #fff;
background-color: black;
}
.popover-darker .popover-body
{
color: #fff;
}
.popover-darker .popover-header
{
border-color: rgba(255, 255, 255, .2);
}
.popover-darker.bs-popover-top .arrow::after,
.popover-darker.bs-popover-auto[x-placement^='top'] .arrow::after
{
border-top-color: black;
}
.popover-darker.bs-popover-right .arrow::after,
.popover-darker.bs-popover-auto[x-placement^='right'] .arrow::after
{
border-right-color: black;
}
.popover-darker.bs-popover-bottom .arrow::after,
.popover-darker.bs-popover-auto[x-placement^='bottom'] .arrow::after
{
border-bottom-color: black;
}
.popover-darker.bs-popover-left .arrow::after,
.popover-darker.bs-popover-auto[x-placement^='left'] .arrow::after
{
border-left-color: black;
}
.progress-wrapper
{
position: relative;
padding-top: 1.5rem;
}
.progress
{
overflow: hidden;
height: 8px;
margin-bottom: 1rem;
border-radius: .25rem;
background-color: #e9ecef;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
}
.progress .sr-only
{
font-size: 13px;
line-height: 20px;
left: 0;
clip: auto;
width: auto;
height: 20px;
margin: 0 0 0 30px;
}
.progress-heading
{
font-size: 14px;
font-weight: 500;
margin: 0 0 2px;
padding: 0;
}
.progress-bar
{
height: auto;
border-radius: 0;
box-shadow: none;
}
.progress-info
{
display: flex;
margin-bottom: .5rem;
align-items: center;
justify-content: space-between;
}
.progress-label span
{
font-size: .625rem;
font-weight: 600;
display: inline-block;
padding: .25rem 1rem;
text-transform: uppercase;
color: #5e72e4;
border-radius: 30px;
background: rgba(94, 114, 228, .1);
}
.progress-percentage
{
text-align: right;
}
.progress-percentage span
{
font-size: .875rem;
font-weight: 600;
display: inline-block;
color: #8898aa;
}
.separator
{
position: absolute;
top: auto;
right: 0;
left: 0;
overflow: hidden;
width: 100%;
height: 150px;
transform: translateZ(0);
pointer-events: none;
}
.separator svg
{
position: absolute;
pointer-events: none;
}
.separator-top
{
top: 0;
bottom: auto;
}
.separator-top svg
{
top: 0;
}
.separator-bottom
{
top: auto;
bottom: 0;
}
.separator-bottom svg
{
bottom: 0;
}
.separator-inverse
{
transform: rotate(180deg);
}
.separator-skew
{
height: 60px;
}
@media (min-width: 1200px)
{
.separator-skew
{
height: 70px;
}
}
.table thead th
{
font-size: .65rem;
padding-top: .75rem;
padding-bottom: .75rem;
letter-spacing: 1px;
text-transform: uppercase;
border-bottom: 1px solid #e9ecef;
}
.table th
{
font-weight: 600;
}
.table td .progress
{
width: 120px;
height: 3px;
margin: 0;
}
.table td,
.table th
{
font-size: .8125rem;
white-space: nowrap;
}
.table.align-items-center td,
.table.align-items-center th
{
vertical-align: middle;
}
.table .thead-dark th
{
color: #4d7bca;
background-color: #1c345d;
}
.table .thead-light th
{
color: #8898aa;
background-color: #f6f9fc;
}
.table-hover tr
{
transition: all .15s ease;
}
@media screen and (prefers-reduced-motion: reduce)
{
.table-hover tr
{
transition: none;
}
}
.table-flush td,
.table-flush th
{
border-right: 0;
border-left: 0;
}
.table-flush tbody tr:first-child td,
.table-flush tbody tr:first-child th
{
border-top: 0;
}
.table-flush tbody tr:last-child td,
.table-flush tbody tr:last-child th
{
border-bottom: 0;
}
.card .table
{
margin-bottom: 0;
}
.card .table td,
.card .table th
{
padding-right: 1.5rem;
padding-left: 1.5rem;
}
p
{
font-size: 1rem;
font-weight: 300;
line-height: 1.7;
}
.lead
{
font-size: 1.25rem;
font-weight: 300;
line-height: 1.7;
margin-top: 1.5rem;
}
.lead + .btn-wrapper
{
margin-top: 3rem;
}
.description
{
font-size: .875rem;
}
.heading
{
font-size: .95rem;
font-weight: 600;
letter-spacing: .025em;
text-transform: uppercase;
}
.heading-small
{
font-size: .75rem;
padding-top: .25rem;
padding-bottom: .25rem;
letter-spacing: .04em;
text-transform: uppercase;
}
.heading-title
{
font-size: 1.375rem;
font-weight: 600;
letter-spacing: .025em;
text-transform: uppercase;
}
.heading-section
{
font-size: 1.375rem;
font-weight: 600;
letter-spacing: .025em;
text-transform: uppercase;
}
.heading-section img
{
display: block;
width: 72px;
height: 72px;
margin-bottom: 1.5rem;
}
.heading-section.text-center img
{
margin-right: auto;
margin-left: auto;
}
.display-1 span,
.display-2 span,
.display-3 span,
.display-4 span
{
font-weight: 300;
display: block;
}
article h4:not(:first-child),
article h5:not(:first-child)
{
margin-top: 3rem;
}
article h4,
article h5
{
margin-bottom: 1.5rem;
}
article figure
{
margin: 3rem 0;
}
article h5 + figure
{
margin-top: 0;
}
.datepicker
{
border-radius: .375rem;
direction: ltr;
}
.datepicker-inline
{
width: 220px;
}
.datepicker-rtl
{
direction: rtl;
}
.datepicker-rtl.dropdown-menu
{
left: auto;
}
.datepicker-rtl table tr td span
{
float: right;
}
.datepicker-dropdown
{
top: 0;
left: 0;
padding: 20px 22px;
box-shadow: 0 50px 100px rgba(50, 50, 93, .1), 0 15px 35px rgba(50, 50, 93, .15), 0 5px 15px rgba(0, 0, 0, .1);
}
.datepicker-dropdown.datepicker-orient-left:before
{
left: 6px;
}
.datepicker-dropdown.datepicker-orient-left:after
{
left: 7px;
}
.datepicker-dropdown.datepicker-orient-right:before
{
right: 6px;
}
.datepicker-dropdown.datepicker-orient-right:after
{
right: 7px;
}
.datepicker-dropdown.datepicker-orient-bottom:before
{
top: -7px;
}
.datepicker-dropdown.datepicker-orient-bottom:after
{
top: -6px;
}
.datepicker-dropdown.datepicker-orient-top:before
{
bottom: -7px;
border-top: 7px solid white;
border-bottom: 0;
}
.datepicker-dropdown.datepicker-orient-top:after
{
bottom: -6px;
border-top: 6px solid #fff;
border-bottom: 0;
}
.datepicker table
{
margin: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
}
.datepicker table tr td
{
border-radius: 50%;
}
.datepicker table tr th
{
font-weight: 500;
border-radius: .375rem;
}
.datepicker table tr td,
.datepicker table tr th
{
font-size: .875rem;
width: 36px;
height: 36px;
transition: all .15s ease;
text-align: center;
border: none;
}
.table-striped .datepicker table tr td,
.table-striped .datepicker table tr th
{
background-color: transparent;
}
.datepicker table tr td.old,
.datepicker table tr td.new
{
color: #adb5bd;
}
.datepicker table tr td.day:hover,
.datepicker table tr td.focused
{
cursor: pointer;
background: white;
}
.datepicker table tr td.disabled,
.datepicker table tr td.disabled:hover
{
cursor: default;
color: #dee2e6;
background: none;
}
.datepicker table tr td.highlighted
{
border-radius: 0;
}
.datepicker table tr td.highlighted.focused
{
background: #5e72e4;
}
.datepicker table tr td.highlighted.disabled,
.datepicker table tr td.highlighted.disabled:active
{
color: #ced4da;
background: #5e72e4;
}
.datepicker table tr td.today
{
background: white;
}
.datepicker table tr td.today.focused
{
background: white;
}
.datepicker table tr td.today.disabled,
.datepicker table tr td.today.disabled:active
{
color: #8898aa;
background: white;
}
.datepicker table tr td.range
{
color: #fff;
border-radius: 0;
background: #5e72e4;
}
.datepicker table tr td.range.focused
{
background: #3b53de;
}
.datepicker table tr td.range.disabled,
.datepicker table tr td.range.disabled:active,
.datepicker table tr td.range.day.disabled:hover
{
color: #8a98eb;
background: #324cdd;
}
.datepicker table tr td.range.highlighted.focused
{
background: #cbd3da;
}
.datepicker table tr td.range.highlighted.disabled,
.datepicker table tr td.range.highlighted.disabled:active
{
color: #dee2e6;
background: #e9ecef;
}
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today.disabled:active
{
color: #fff;
background: #5e72e4;
}
.datepicker table tr td.day.range-start
{
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.datepicker table tr td.day.range-end
{
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.datepicker table tr td.day.range-start.range-end
{
border-radius: 50%;
}
.datepicker table tr td.selected,
.datepicker table tr td.selected.highlighted,
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected.highlighted:hover,
.datepicker table tr td.day.range:hover
{
color: #fff;
background: #5e72e4;
}
.datepicker table tr td.active,
.datepicker table tr td.active.highlighted,
.datepicker table tr td.active:hover,
.datepicker table tr td.active.highlighted:hover
{
color: #fff;
background: #5e72e4;
box-shadow: none;
}
.datepicker table tr td span
{
line-height: 54px;
display: block;
float: left;
width: 23%;
height: 54px;
margin: 1%;
cursor: pointer;
border-radius: 4px;
}
.datepicker table tr td span:hover,
.datepicker table tr td span.focused
{
background: #e9ecef;
}
.datepicker table tr td span.disabled,
.datepicker table tr td span.disabled:hover
{
cursor: default;
color: #dee2e6;
background: none;
}
.datepicker table tr td span.active,
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active.disabled:hover
{
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
}
.datepicker table tr td span.old,
.datepicker table tr td span.new
{
color: #8898aa;
}
.datepicker .datepicker-switch
{
width: 145px;
}
.datepicker .datepicker-switch,
.datepicker .prev,
.datepicker .next,
.datepicker tfoot tr th
{
cursor: pointer;
}
.datepicker .datepicker-switch:hover,
.datepicker .prev:hover,
.datepicker .next:hover,
.datepicker tfoot tr th:hover
{
background: #e9ecef;
}
.datepicker .prev.disabled,
.datepicker .next.disabled
{
visibility: hidden;
}
.datepicker .cw
{
font-size: 10px;
width: 12px;
padding: 0 2px 0 5px;
vertical-align: middle;
}
.noUi-target,
.noUi-target *
{
box-sizing: border-box;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
touch-action: none;
}
.noUi-target
{
position: relative;
direction: ltr;
}
.noUi-base,
.noUi-connects
{
position: relative;
z-index: 1;
width: 100%;
height: 100%;
}
.noUi-connects
{
z-index: 0;
overflow: hidden;
}
.noUi-connect,
.noUi-origin
{
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
transform-origin: 0 0;
will-change: transform;
}
html:not([dir='rtl']) .noUi-horizontal .noUi-origin
{
right: 0;
left: auto;
}
.noUi-vertical .noUi-origin
{
width: 0;
}
.noUi-horizontal .noUi-origin
{
height: 0;
}
.noUi-handle
{
position: absolute;
}
.noUi-state-tap .noUi-connect,
.noUi-state-tap .noUi-origin
{
transition: transform .3s;
}
.noUi-state-drag *
{
cursor: inherit !important;
}
.noUi-horizontal
{
height: 5px;
}
.noUi-horizontal .noUi-handle
{
top: -6px;
left: -17px;
width: 34px;
height: 28px;
}
.noUi-vertical
{
width: 5px;
}
.noUi-vertical .noUi-handle
{
top: -17px;
left: -6px;
width: 28px;
height: 34px;
}
html:not([dir='rtl']) .noUi-horizontal .noUi-handle
{
right: -17px;
left: auto;
}
.noUi-connects
{
border-radius: 3px;
}
.noUi-connect
{
background: #5e72e4;
}
.noUi-draggable
{
cursor: ew-resize;
}
.noUi-vertical .noUi-draggable
{
cursor: ns-resize;
}
.noUi-handle
{
cursor: default;
border: 1px solid #d9d9d9;
border-radius: 3px;
outline: none;
background: #fff;
box-shadow: inset 0 0 1px #fff, inset 0 1px 7px #ebebeb, 0 3px 6px -3px #bbb;
}
.noUi-active
{
outline: none;
}
/* Disabled state;
*/
[disabled] .noUi-connect
{
background: #b8b8b8;
}
[disabled].noUi-target,
[disabled].noUi-handle,
[disabled] .noUi-handle
{
cursor: not-allowed;
}
/* Base;
*
*/
.noUi-pips,
.noUi-pips *
{
box-sizing: border-box;
}
.noUi-pips
{
position: absolute;
color: #999;
}
/* Values;
*
*/
.noUi-value
{
position: absolute;
text-align: center;
white-space: nowrap;
}
.noUi-value-sub
{
font-size: 10px;
color: #ccc;
}
/* Markings;
*
*/
.noUi-marker
{
position: absolute;
background: #ccc;
}
.noUi-marker-sub
{
background: #aaa;
}
.noUi-marker-large
{
background: #aaa;
}
/* Horizontal layout;
*
*/
.noUi-pips-horizontal
{
top: 100%;
left: 0;
width: 100%;
height: 80px;
padding: 10px 0;
}
.noUi-value-horizontal
{
transform: translate(-50%, 50%);
}
.noUi-rtl .noUi-value-horizontal
{
transform: translate(50%, 50%);
}
.noUi-marker-horizontal.noUi-marker
{
width: 2px;
height: 5px;
margin-left: -1px;
}
.noUi-marker-horizontal.noUi-marker-sub
{
height: 10px;
}
.noUi-marker-horizontal.noUi-marker-large
{
height: 15px;
}
/* Vertical layout;
*
*/
.noUi-pips-vertical
{
top: 0;
left: 100%;
height: 100%;
padding: 0 10px;
}
.noUi-value-vertical
{
padding-left: 25px;
transform: translate(0, -50%, 0);
}
.noUi-rtl .noUi-value-vertical
{
transform: translate(0, 50%);
}
.noUi-marker-vertical.noUi-marker
{
width: 5px;
height: 2px;
margin-top: -1px;
}
.noUi-marker-vertical.noUi-marker-sub
{
width: 10px;
}
.noUi-marker-vertical.noUi-marker-large
{
width: 15px;
}
.noUi-tooltip
{
position: absolute;
display: block;
padding: 5px;
text-align: center;
white-space: nowrap;
color: #000;
border: 1px solid #d9d9d9;
border-radius: 3px;
background: #fff;
}
.noUi-horizontal .noUi-tooltip
{
bottom: 120%;
left: 50%;
transform: translate(-50%, 0);
}
.noUi-vertical .noUi-tooltip
{
top: 50%;
right: 120%;
transform: translate(0, -50%);
}
.noUi-target
{
margin: 15px 0;
cursor: pointer;
border: 0;
border-radius: 5px;
background: #eceeef;
box-shadow: inset 0 1px 2px rgba(90, 97, 105, .1);
}
.noUi-horizontal
{
height: 5px;
}
html:not([dir='rtl']) .noUi-horizontal .noUi-handle
{
right: -10px;
}
.noUi-vertical
{
width: 5px;
}
.noUi-connect
{
background: #5e72e4;
box-shadow: none;
}
.noUi-horizontal .noUi-handle,
.noUi-vertical .noUi-handle
{
top: -5px;
width: 15px;
height: 15px;
cursor: pointer;
transition: box-shadow .15s, transform .15s;
border: 0;
border-radius: 100%;
background-color: #5e72e4;
box-shadow: none;
}
.noUi-horizontal .noUi-handle.noUi-active,
.noUi-vertical .noUi-handle.noUi-active
{
box-shadow: 0 0 0 2px #5e72e4;
}
.input-slider--cyan .noUi-connect
{
background: #2bffc6;
}
/* Disabled state */
[disabled] .noUi-connect,
[disabled].noUi-connect
{
background: #b2b2b2;
}
[disabled] .noUi-handle,
[disabled].noUi-origin
{
cursor: not-allowed;
}
/* Range slider value labels */
.range-slider-value
{
font-size: .75rem;
font-weight: 500;
padding: .4em .8em .3em .85em;
color: #fff;
border-radius: 10px;
background-color: rgba(33, 37, 41, .7);
}
.range-slider-wrapper .upper-info
{
font-weight: 400;
margin-bottom: 5px;
}
.input-slider-value-output
{
font-size: 11px;
position: relative;
top: 12px;
padding: 4px 8px;
color: #fff;
border-radius: 2px;
background: #333;
}
.input-slider-value-output:after
{
position: absolute;
bottom: 100%;
left: 10px;
width: 0;
height: 0;
margin-left: -4px;
content: ' ';
pointer-events: none;
border: solid transparent;
border-width: 4px;
border-color: rgba(136, 183, 213, 0);
border-bottom-color: #333;
}
.input-slider-value-output.left:after
{
right: auto;
left: 10px;
}
.input-slider-value-output.right:after
{
right: 10px;
left: auto;
}
.scrollbar-inner
{
height: 100%;
}
.scrollbar-inner:not(:hover) .scroll-element
{
opacity: 0;
}
.scrollbar-inner .scroll-element
{
margin-right: 2px;
transition: opacity 300ms;
}
.scrollbar-inner .scroll-element .scroll-bar,
.scrollbar-inner .scroll-element .scroll-element_track
{
transition: background-color 300ms;
}
.scrollbar-inner .scroll-element .scroll-element_track
{
background-color: transparent;
}
.scrollbar-inner .scroll-element.scroll-y
{
right: 0;
width: 3px;
}
.scrollbar-inner .scroll-element.scroll-x
{
bottom: 0;
height: 3px;
}
================================================
FILE: assets/css/bootstrap.css
================================================
/*!
* Bootstrap v4.0.0 (https://getbootstrap.com)
* Copyright 2011-2018 The Bootstrap Authors
* Copyright 2011-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
:root {
--blue: #007bff;
--indigo: #6610f2;
--purple: #6f42c1;
--pink: #e83e8c;
--red: #dc3545;
--orange: #fd7e14;
--yellow: #ffc107;
--green: #28a745;
--teal: #20c997;
--cyan: #17a2b8;
--white: #fff;
--gray: #6c757d;
--gray-dark: #343a40;
--primary: #007bff;
--secondary: #6c757d;
--success: #28a745;
--info: #17a2b8;
--warning: #ffc107;
--danger: #dc3545;
--light: #f8f9fa;
--dark: #343a40;
--breakpoint-xs: 0;
--breakpoint-sm: 576px;
--breakpoint-md: 768px;
--breakpoint-lg: 992px;
--breakpoint-xl: 1200px;
--font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
--font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: transparent;
}
@-ms-viewport {
width: device-width;
}
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
text-align: left;
background-color: #fff;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 0.5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: .5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
dfn {
font-style: italic;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
a {
color: #007bff;
text-decoration: none;
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:hover {
color: #0056b3;
text-decoration: underline;
}
a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre,
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
-ms-overflow-style: scrollbar;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
svg:not(:root) {
overflow: hidden;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #6c757d;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
}
label {
display: inline-block;
margin-bottom: .5rem;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
cursor: pointer;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
margin-bottom: 0.5rem;
font-family: inherit;
font-weight: 500;
line-height: 1.2;
color: inherit;
}
h1, .h1 {
font-size: 2.5rem;
}
h2, .h2 {
font-size: 2rem;
}
h3, .h3 {
font-size: 1.75rem;
}
h4, .h4 {
font-size: 1.5rem;
}
h5, .h5 {
font-size: 1.25rem;
}
h6, .h6 {
font-size: 1rem;
}
.lead {
font-size: 1.25rem;
font-weight: 300;
}
.display-1 {
font-size: 6rem;
font-weight: 300;
line-height: 1.2;
}
.display-2 {
font-size: 5.5rem;
font-weight: 300;
line-height: 1.2;
}
.display-3 {
font-size: 4.5rem;
font-weight: 300;
line-height: 1.2;
}
.display-4 {
font-size: 3.5rem;
font-weight: 300;
line-height: 1.2;
}
hr {
margin-top: 1rem;
margin-bottom: 1rem;
border: 0;
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
small,
.small {
font-size: 80%;
font-weight: 400;
}
mark,
.mark {
padding: 0.2em;
background-color: #fcf8e3;
}
.list-unstyled {
padding-left: 0;
list-style: none;
}
.list-inline {
padding-left: 0;
list-style: none;
}
.list-inline-item {
display: inline-block;
}
.list-inline-item:not(:last-child) {
margin-right: 0.5rem;
}
.initialism {
font-size: 90%;
text-transform: uppercase;
}
.blockquote {
margin-bottom: 1rem;
font-size: 1.25rem;
}
.blockquote-footer {
display: block;
font-size: 80%;
color: #6c757d;
}
.blockquote-footer::before {
content: "\2014 \00A0";
}
.img-fluid {
max-width: 100%;
height: auto;
}
.img-thumbnail {
padding: 0.25rem;
background-color: #fff;
border: 1px solid #dee2e6;
border-radius: 0.25rem;
max-width: 100%;
height: auto;
}
.figure {
display: inline-block;
}
.figure-img {
margin-bottom: 0.5rem;
line-height: 1;
}
.figure-caption {
font-size: 90%;
color: #6c757d;
}
code,
kbd,
pre,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
code {
font-size: 87.5%;
color: #e83e8c;
word-break: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 87.5%;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 100%;
font-weight: 700;
}
pre {
display: block;
font-size: 87.5%;
color: #212529;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
.pre-scrollable {
max-height: 340px;
overflow-y: scroll;
}
.container {
width: 100%;
padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;
}
@media (min-width: 576px) {
.container {
max-width: 540px;
}
}
@media (min-width: 768px) {
.container {
max-width: 720px;
}
}
@media (min-width: 992px) {
.container {
max-width: 960px;
}
}
@media (min-width: 1200px) {
.container {
max-width: 1140px;
}
}
.container-fluid {
width: 100%;
padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;
}
.row {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-right: -15px;
margin-left: -15px;
}
.no-gutters {
margin-right: 0;
margin-left: 0;
}
.no-gutters > .col,
.no-gutters > [class*="col-"] {
padding-right: 0;
padding-left: 0;
}
.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, .col,
.col-auto, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm,
.col-sm-auto, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-md,
.col-md-auto, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg,
.col-lg-auto, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl,
.col-xl-auto {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
.col {
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
}
.col-auto {
-webkit-box-flex: 0;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
width: auto;
max-width: none;
}
.col-1 {
-webkit-box-flex: 0;
-ms-flex: 0 0 8.333333%;
flex: 0 0 8.333333%;
max-width: 8.333333%;
}
.col-2 {
-webkit-box-flex: 0;
-ms-flex: 0 0 16.666667%;
flex: 0 0 16.666667%;
max-width: 16.666667%;
}
.col-3 {
-webkit-box-flex: 0;
-ms-flex: 0 0 25%;
flex: 0 0 25%;
max-width: 25%;
}
.col-4 {
-webkit-box-flex: 0;
-ms-flex: 0 0 33.333333%;
flex: 0 0 33.333333%;
max-width: 33.333333%;
}
.col-5 {
-webkit-box-flex: 0;
-ms-flex: 0 0 41.666667%;
flex: 0 0 41.666667%;
max-width: 41.666667%;
}
.col-6 {
-webkit-box-flex: 0;
-ms-flex: 0 0 50%;
flex: 0 0 50%;
max-width: 50%;
}
.col-7 {
-webkit-box-flex: 0;
-ms-flex: 0 0 58.333333%;
flex: 0 0 58.333333%;
max-width: 58.333333%;
}
.col-8 {
-webkit-box-flex: 0;
-ms-flex: 0 0 66.666667%;
flex: 0 0 66.666667%;
max-width: 66.666667%;
}
.col-9 {
-webkit-box-flex: 0;
-ms-flex: 0 0 75%;
flex: 0 0 75%;
max-width: 75%;
}
.col-10 {
-webkit-box-flex: 0;
-ms-flex: 0 0 83.333333%;
flex: 0 0 83.333333%;
max-width: 83.333333%;
}
.col-11 {
-webkit-box-flex: 0;
-ms-flex: 0 0 91.666667%;
flex: 0 0 91.666667%;
max-width: 91.666667%;
}
.col-12 {
-webkit-box-flex: 0;
-ms-flex: 0 0 100%;
flex: 0 0 100%;
max-width: 100%;
}
.order-first {
-webkit-box-ordinal-group: 0;
-ms-flex-order: -1;
order: -1;
}
.order-last {
-webkit-box-ordinal-group: 14;
-ms-flex-order: 13;
order: 13;
}
.order-0 {
-webkit-box-ordinal-group: 1;
-ms-flex-order: 0;
order: 0;
}
.order-1 {
-webkit-box-ordinal-group: 2;
-ms-flex-order: 1;
order: 1;
}
.order-2 {
-webkit-box-ordinal-group: 3;
-ms-flex-order: 2;
order: 2;
}
.order-3 {
-webkit-box-ordinal-group: 4;
-ms-flex-order: 3;
order: 3;
}
.order-4 {
-webkit-box-ordinal-group: 5;
-ms-flex-order: 4;
order: 4;
}
.order-5 {
-webkit-box-ordinal-group: 6;
-ms-flex-order: 5;
order: 5;
}
.order-6 {
-webkit-box-ordinal-group: 7;
-ms-flex-order: 6;
order: 6;
}
.order-7 {
-webkit-box-ordinal-group: 8;
-ms-flex-order: 7;
order: 7;
}
.order-8 {
-webkit-box-ordinal-group: 9;
-ms-flex-order: 8;
order: 8;
}
.order-9 {
-webkit-box-ordinal-group: 10;
-ms-flex-order: 9;
order: 9;
}
.order-10 {
-webkit-box-ordinal-group: 11;
-ms-flex-order: 10;
order: 10;
}
.order-11 {
-webkit-box-ordinal-group: 12;
-ms-flex-order: 11;
order: 11;
}
.order-12 {
-webkit-box-ordinal-group: 13;
-ms-flex-order: 12;
order: 12;
}
.offset-1 {
margin-left: 8.333333%;
}
.offset-2 {
margin-left: 16.666667%;
}
.offset-3 {
margin-left: 25%;
}
.offset-4 {
margin-left: 33.333333%;
}
.offset-5 {
margin-left: 41.666667%;
}
.offset-6 {
margin-left: 50%;
}
.offset-7 {
margin-left: 58.333333%;
}
.offset-8 {
margin-left: 66.666667%;
}
.offset-9 {
margin-left: 75%;
}
.offset-10 {
margin-left: 83.333333%;
}
.offset-11 {
margin-left: 91.666667%;
}
@media (min-width: 576px) {
.col-sm {
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
}
.col-sm-auto {
-webkit-box-flex: 0;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
width: auto;
max-width: none;
}
.col-sm-1 {
-webkit-box-flex: 0;
-ms-flex: 0 0 8.333333%;
flex: 0 0 8.333333%;
max-width: 8.333333%;
}
.col-sm-2 {
-webkit-box-flex: 0;
-ms-flex: 0 0 16.666667%;
flex: 0 0 16.666667%;
max-width: 16.666667%;
}
.col-sm-3 {
-webkit-box-flex: 0;
-ms-flex: 0 0 25%;
flex: 0 0 25%;
max-width: 25%;
}
.col-sm-4 {
-webkit-box-flex: 0;
-ms-flex: 0 0 33.333333%;
flex: 0 0 33.333333%;
max-width: 33.333333%;
}
.col-sm-5 {
-webkit-box-flex: 0;
-ms-flex: 0 0 41.666667%;
flex: 0 0 41.666667%;
max-width: 41.666667%;
}
.col-sm-6 {
-webkit-box-flex: 0;
-ms-flex: 0 0 50%;
flex: 0 0 50%;
max-width: 50%;
}
.col-sm-7 {
-webkit-box-flex: 0;
-ms-flex: 0 0 58.333333%;
flex: 0 0 58.333333%;
max-width: 58.333333%;
}
.col-sm-8 {
-webkit-box-flex: 0;
-ms-flex: 0 0 66.666667%;
flex: 0 0 66.666667%;
max-width: 66.666667%;
}
.col-sm-9 {
-webkit-box-flex: 0;
-ms-flex: 0 0 75%;
flex: 0 0 75%;
max-width: 75%;
}
.col-sm-10 {
-webkit-box-flex: 0;
-ms-flex: 0 0 83.333333%;
flex: 0 0 83.333333%;
max-width: 83.333333%;
}
.col-sm-11 {
-webkit-box-flex: 0;
-ms-flex: 0 0 91.666667%;
flex: 0 0 91.666667%;
max-width: 91.666667%;
}
.col-sm-12 {
-webkit-box-flex: 0;
-ms-flex: 0 0 100%;
flex: 0 0 100%;
max-width: 100%;
}
.order-sm-first {
-webkit-box-ordinal-group: 0;
-ms-flex-order: -1;
order: -1;
}
.order-sm-last {
-webkit-box-ordinal-group: 14;
-ms-flex-order: 13;
order: 13;
}
.order-sm-0 {
-webkit-box-ordinal-group: 1;
-ms-flex-order: 0;
order: 0;
}
.order-sm-1 {
-webkit-box-ordinal-group: 2;
-ms-flex-order: 1;
order: 1;
}
.order-sm-2 {
-webkit-box-ordinal-group: 3;
-ms-flex-order: 2;
order: 2;
}
.order-sm-3 {
-webkit-box-ordinal-group: 4;
-ms-flex-order: 3;
order: 3;
}
.order-sm-4 {
-webkit-box-ordinal-group: 5;
-ms-flex-order: 4;
order: 4;
}
.order-sm-5 {
-webkit-box-ordinal-group: 6;
-ms-flex-order: 5;
order: 5;
}
.order-sm-6 {
-webkit-box-ordinal-group: 7;
-ms-flex-order: 6;
order: 6;
}
.order-sm-7 {
-webkit-box-ordinal-group: 8;
-ms-flex-order: 7;
order: 7;
}
.order-sm-8 {
-webkit-box-ordinal-group: 9;
-ms-flex-order: 8;
order: 8;
}
.order-sm-9 {
-webkit-box-ordinal-group: 10;
-ms-flex-order: 9;
order: 9;
}
.order-sm-10 {
-webkit-box-ordinal-group: 11;
-ms-flex-order: 10;
order: 10;
}
.order-sm-11 {
-webkit-box-ordinal-group: 12;
-ms-flex-order: 11;
order: 11;
}
.order-sm-12 {
-webkit-box-ordinal-group: 13;
-ms-flex-order: 12;
order: 12;
}
.offset-sm-0 {
margin-left: 0;
}
.offset-sm-1 {
margin-left: 8.333333%;
}
.offset-sm-2 {
margin-left: 16.666667%;
}
.offset-sm-3 {
margin-left: 25%;
}
.offset-sm-4 {
margin-left: 33.333333%;
}
.offset-sm-5 {
margin-left: 41.666667%;
}
.offset-sm-6 {
margin-left: 50%;
}
.offset-sm-7 {
margin-left: 58.333333%;
}
.offset-sm-8 {
margin-left: 66.666667%;
}
.offset-sm-9 {
margin-left: 75%;
}
.offset-sm-10 {
margin-left: 83.333333%;
}
.offset-sm-11 {
margin-left: 91.666667%;
}
}
@media (min-width: 768px) {
.col-md {
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
}
.col-md-auto {
-webkit-box-flex: 0;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
width: auto;
max-width: none;
}
.col-md-1 {
-webkit-box-flex: 0;
-ms-flex: 0 0 8.333333%;
flex: 0 0 8.333333%;
max-width: 8.333333%;
}
.col-md-2 {
-webkit-box-flex: 0;
-ms-flex: 0 0 16.666667%;
flex: 0 0 16.666667%;
max-width: 16.666667%;
}
.col-md-3 {
-webkit-box-flex: 0;
-ms-flex: 0 0 25%;
flex: 0 0 25%;
max-width: 25%;
}
.col-md-4 {
-webkit-box-flex: 0;
-ms-flex: 0 0 33.333333%;
flex: 0 0 33.333333%;
max-width: 33.333333%;
}
.col-md-5 {
-webkit-box-flex: 0;
-ms-flex: 0 0 41.666667%;
flex: 0 0 41.666667%;
max-width: 41.666667%;
}
.col-md-6 {
-webkit-box-flex: 0;
-ms-flex: 0 0 50%;
flex: 0 0 50%;
max-width: 50%;
}
.col-md-7 {
-webkit-box-flex: 0;
-ms-flex: 0 0 58.333333%;
flex: 0 0 58.333333%;
max-width: 58.333333%;
}
.col-md-8 {
-webkit-box-flex: 0;
-ms-flex: 0 0 66.666667%;
flex: 0 0 66.666667%;
max-width: 66.666667%;
}
.col-md-9 {
-webkit-box-flex: 0;
-ms-flex: 0 0 75%;
flex: 0 0 75%;
max-width: 75%;
}
.col-md-10 {
-webkit-box-flex: 0;
-ms-flex: 0 0 83.333333%;
flex: 0 0 83.333333%;
max-width: 83.333333%;
}
.col-md-11 {
-webkit-box-flex: 0;
-ms-flex: 0 0 91.666667%;
flex: 0 0 91.666667%;
max-width: 91.666667%;
}
.col-md-12 {
-webkit-box-flex: 0;
-ms-flex: 0 0 100%;
flex: 0 0 100%;
max-width: 100%;
}
.order-md-first {
-webkit-box-ordinal-group: 0;
-ms-flex-order: -1;
order: -1;
}
.order-md-last {
-webkit-box-ordinal-group: 14;
-ms-flex-order: 13;
order: 13;
}
.order-md-0 {
-webkit-box-ordinal-group: 1;
-ms-flex-order: 0;
order: 0;
}
.order-md-1 {
-webkit-box-ordinal-group: 2;
-ms-flex-order: 1;
order: 1;
}
.order-md-2 {
-webkit-box-ordinal-group: 3;
-ms-flex-order: 2;
order: 2;
}
.order-md-3 {
-webkit-box-ordinal-group: 4;
-ms-flex-order: 3;
order: 3;
}
.order-md-4 {
-webkit-box-ordinal-group: 5;
-ms-flex-order: 4;
order: 4;
}
.order-md-5 {
-webkit-box-ordinal-group: 6;
-ms-flex-order: 5;
order: 5;
}
.order-md-6 {
-webkit-box-ordinal-group: 7;
-ms-flex-order: 6;
order: 6;
}
.order-md-7 {
-webkit-box-ordinal-group: 8;
-ms-flex-order: 7;
order: 7;
}
.order-md-8 {
-webkit-box-ordinal-group: 9;
-ms-flex-order: 8;
order: 8;
}
.order-md-9 {
-webkit-box-ordinal-group: 10;
-ms-flex-order: 9;
order: 9;
}
.order-md-10 {
-webkit-box-ordinal-group: 11;
-ms-flex-order: 10;
order: 10;
}
.order-md-11 {
-webkit-box-ordinal-group: 12;
-ms-flex-order: 11;
order: 11;
}
.order-md-12 {
-webkit-box-ordinal-group: 13;
-ms-flex-order: 12;
order: 12;
}
.offset-md-0 {
margin-left: 0;
}
.offset-md-1 {
margin-left: 8.333333%;
}
.offset-md-2 {
margin-left: 16.666667%;
}
.offset-md-3 {
margin-left: 25%;
}
.offset-md-4 {
margin-left: 33.333333%;
}
.offset-md-5 {
margin-left: 41.666667%;
}
.offset-md-6 {
margin-left: 50%;
}
.offset-md-7 {
margin-left: 58.333333%;
}
.offset-md-8 {
margin-left: 66.666667%;
}
.offset-md-9 {
margin-left: 75%;
}
.offset-md-10 {
margin-left: 83.333333%;
}
.offset-md-11 {
margin-left: 91.666667%;
}
}
@media (min-width: 992px) {
.col-lg {
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
}
.col-lg-auto {
-webkit-box-flex: 0;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
width: auto;
max-width: none;
}
.col-lg-1 {
-webkit-box-flex: 0;
-ms-flex: 0 0 8.333333%;
flex: 0 0 8.333333%;
max-width: 8.333333%;
}
.col-lg-2 {
-webkit-box-flex: 0;
-ms-flex: 0 0 16.666667%;
flex: 0 0 16.666667%;
max-width: 16.666667%;
}
.col-lg-3 {
-webkit-box-flex: 0;
-ms-flex: 0 0 25%;
flex: 0 0 25%;
max-width: 25%;
}
.col-lg-4 {
-webkit-box-flex: 0;
-ms-flex: 0 0 33.333333%;
flex: 0 0 33.333333%;
max-width: 33.333333%;
}
.col-lg-5 {
-webkit-box-flex: 0;
-ms-flex: 0 0 41.666667%;
flex: 0 0 41.666667%;
max-width: 41.666667%;
}
.col-lg-6 {
-webkit-box-flex: 0;
-ms-flex: 0 0 50%;
flex: 0 0 50%;
max-width: 50%;
}
.col-lg-7 {
-webkit-box-flex: 0;
-ms-flex: 0 0 58.333333%;
flex: 0 0 58.333333%;
max-width: 58.333333%;
}
.col-lg-8 {
-webkit-box-flex: 0;
-ms-flex: 0 0 66.666667%;
flex: 0 0 66.666667%;
max-width: 66.666667%;
}
.col-lg-9 {
-webkit-box-flex: 0;
-ms-flex: 0 0 75%;
flex: 0 0 75%;
max-width: 75%;
}
.col-lg-10 {
-webkit-box-flex: 0;
-ms-flex: 0 0 83.333333%;
flex: 0 0 83.333333%;
max-width: 83.333333%;
}
.col-lg-11 {
-webkit-box-flex: 0;
-ms-flex: 0 0 91.666667%;
flex: 0 0 91.666667%;
max-width: 91.666667%;
}
.col-lg-12 {
-webkit-box-flex: 0;
-ms-flex: 0 0 100%;
flex: 0 0 100%;
max-width: 100%;
}
.order-lg-first {
-webkit-box-ordinal-group: 0;
-ms-flex-order: -1;
order: -1;
}
.order-lg-last {
-webkit-box-ordinal-group: 14;
-ms-flex-order: 13;
order: 13;
}
.order-lg-0 {
-webkit-box-ordinal-group: 1;
-ms-flex-order: 0;
order: 0;
}
.order-lg-1 {
-webkit-box-ordinal-group: 2;
-ms-flex-order: 1;
order: 1;
}
.order-lg-2 {
-webkit-box-ordinal-group: 3;
-ms-flex-order: 2;
order: 2;
}
.order-lg-3 {
-webkit-box-ordinal-group: 4;
-ms-flex-order: 3;
order: 3;
}
.order-lg-4 {
-webkit-box-ordinal-group: 5;
-ms-flex-order: 4;
order: 4;
}
.order-lg-5 {
-webkit-box-ordinal-group: 6;
-ms-flex-order: 5;
order: 5;
}
.order-lg-6 {
-webkit-box-ordinal-group: 7;
-ms-flex-order: 6;
order: 6;
}
.order-lg-7 {
-webkit-box-ordinal-group: 8;
-ms-flex-order: 7;
order: 7;
}
.order-lg-8 {
-webkit-box-ordinal-group: 9;
-ms-flex-order: 8;
order: 8;
}
.order-lg-9 {
-webkit-box-ordinal-group: 10;
-ms-flex-order: 9;
order: 9;
}
.order-lg-10 {
-webkit-box-ordinal-group: 11;
-ms-flex-order: 10;
order: 10;
}
.order-lg-11 {
-webkit-box-ordinal-group: 12;
-ms-flex-order: 11;
order: 11;
}
.order-lg-12 {
-webkit-box-ordinal-group: 13;
-ms-flex-order: 12;
order: 12;
}
.offset-lg-0 {
margin-left: 0;
}
.offset-lg-1 {
margin-left: 8.333333%;
}
.offset-lg-2 {
margin-left: 16.666667%;
}
.offset-lg-3 {
margin-left: 25%;
}
.offset-lg-4 {
margin-left: 33.333333%;
}
.offset-lg-5 {
margin-left: 41.666667%;
}
.offset-lg-6 {
margin-left: 50%;
}
.offset-lg-7 {
margin-left: 58.333333%;
}
.offset-lg-8 {
margin-left: 66.666667%;
}
.offset-lg-9 {
margin-left: 75%;
}
.offset-lg-10 {
margin-left: 83.333333%;
}
.offset-lg-11 {
margin-left: 91.666667%;
}
}
@media (min-width: 1200px) {
.col-xl {
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
}
.col-xl-auto {
-webkit-box-flex: 0;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
width: auto;
max-width: none;
}
.col-xl-1 {
-webkit-box-flex: 0;
-ms-flex: 0 0 8.333333%;
flex: 0 0 8.333333%;
max-width: 8.333333%;
}
.col-xl-2 {
-webkit-box-flex: 0;
-ms-flex: 0 0 16.666667%;
flex: 0 0 16.666667%;
max-width: 16.666667%;
}
.col-xl-3 {
-webkit-box-flex: 0;
-ms-flex: 0 0 25%;
flex: 0 0 25%;
max-width: 25%;
}
.col-xl-4 {
-webkit-box-flex: 0;
-ms-flex: 0 0 33.333333%;
flex: 0 0 33.333333%;
max-width: 33.333333%;
}
.col-xl-5 {
-webkit-box-flex: 0;
-ms-flex: 0 0 41.666667%;
flex: 0 0 41.666667%;
max-width: 41.666667%;
}
.col-xl-6 {
-webkit-box-flex: 0;
-ms-flex: 0 0 50%;
flex: 0 0 50%;
max-width: 50%;
}
.col-xl-7 {
-webkit-box-flex: 0;
-ms-flex: 0 0 58.333333%;
flex: 0 0 58.333333%;
max-width: 58.333333%;
}
.col-xl-8 {
-webkit-box-flex: 0;
-ms-flex: 0 0 66.666667%;
flex: 0 0 66.666667%;
max-width: 66.666667%;
}
.col-xl-9 {
-webkit-box-flex: 0;
-ms-flex: 0 0 75%;
flex: 0 0 75%;
max-width: 75%;
}
.col-xl-10 {
-webkit-box-flex: 0;
-ms-flex: 0 0 83.333333%;
flex: 0 0 83.333333%;
max-width: 83.333333%;
}
.col-xl-11 {
-webkit-box-flex: 0;
-ms-flex: 0 0 91.666667%;
flex: 0 0 91.666667%;
max-width: 91.666667%;
}
.col-xl-12 {
-webkit-box-flex: 0;
-ms-flex: 0 0 100%;
flex: 0 0 100%;
max-width: 100%;
}
.order-xl-first {
-webkit-box-ordinal-group: 0;
-ms-flex-order: -1;
order: -1;
}
.order-xl-last {
-webkit-box-ordinal-group: 14;
-ms-flex-order: 13;
order: 13;
}
.order-xl-0 {
-webkit-box-ordinal-group: 1;
-ms-flex-order: 0;
order: 0;
}
.order-xl-1 {
-webkit-box-ordinal-group: 2;
-ms-flex-order: 1;
order: 1;
}
.order-xl-2 {
-webkit-box-ordinal-group: 3;
-ms-flex-order: 2;
order: 2;
}
.order-xl-3 {
-webkit-box-ordinal-group: 4;
-ms-flex-order: 3;
order: 3;
}
.order-xl-4 {
-webkit-box-ordinal-group: 5;
-ms-flex-order: 4;
order: 4;
}
.order-xl-5 {
-webkit-box-ordinal-group: 6;
-ms-flex-order: 5;
order: 5;
}
.order-xl-6 {
-webkit-box-ordinal-group: 7;
-ms-flex-order: 6;
order: 6;
}
.order-xl-7 {
-webkit-box-ordinal-group: 8;
-ms-flex-order: 7;
order: 7;
}
.order-xl-8 {
-webkit-box-ordinal-group: 9;
-ms-flex-order: 8;
order: 8;
}
.order-xl-9 {
-webkit-box-ordinal-group: 10;
-ms-flex-order: 9;
order: 9;
}
.order-xl-10 {
-webkit-box-ordinal-group: 11;
-ms-flex-order: 10;
order: 10;
}
.order-xl-11 {
-webkit-box-ordinal-group: 12;
-ms-flex-order: 11;
order: 11;
}
.order-xl-12 {
-webkit-box-ordinal-group: 13;
-ms-flex-order: 12;
order: 12;
}
.offset-xl-0 {
margin-left: 0;
}
.offset-xl-1 {
margin-left: 8.333333%;
}
.offset-xl-2 {
margin-left: 16.666667%;
}
.offset-xl-3 {
margin-left: 25%;
}
.offset-xl-4 {
margin-left: 33.333333%;
}
.offset-xl-5 {
margin-left: 41.666667%;
}
.offset-xl-6 {
margin-left: 50%;
}
.offset-xl-7 {
margin-left: 58.333333%;
}
.offset-xl-8 {
margin-left: 66.666667%;
}
.offset-xl-9 {
margin-left: 75%;
}
.offset-xl-10 {
margin-left: 83.333333%;
}
.offset-xl-11 {
margin-left: 91.666667%;
}
}
.table {
width: 100%;
max-width: 100%;
margin-bottom: 1rem;
background-color: transparent;
}
.table th,
.table td {
padding: 0.75rem;
vertical-align: top;
border-top: 1px solid #dee2e6;
}
.table thead th {
vertical-align: bottom;
border-bottom: 2px solid #dee2e6;
}
.table tbody + tbody {
border-top: 2px solid #dee2e6;
}
.table .table {
background-color: #fff;
}
.table-sm th,
.table-sm td {
padding: 0.3rem;
}
.table-bordered {
border: 1px solid #dee2e6;
}
.table-bordered th,
.table-bordered td {
border: 1px solid #dee2e6;
}
.table-bordered thead th,
.table-bordered thead td {
border-bottom-width: 2px;
}
.table-striped tbody tr:nth-of-type(odd) {
background-color: rgba(0, 0, 0, 0.05);
}
.table-hover tbody tr:hover {
background-color: rgba(0, 0, 0, 0.075);
}
.table-primary,
.table-primary > th,
.table-primary > td {
background-color: #b8daff;
}
.table-hover .table-primary:hover {
background-color: #9fcdff;
}
.table-hover .table-primary:hover > td,
.table-hover .table-primary:hover > th {
background-color: #9fcdff;
}
.table-secondary,
.table-secondary > th,
.table-secondary > td {
background-color: #d6d8db;
}
.table-hover .table-secondary:hover {
background-color: #c8cbcf;
}
.table-hover .table-secondary:hover > td,
.table-hover .table-secondary:hover > th {
background-color: #c8cbcf;
}
.table-success,
.table-success > th,
.table-success > td {
background-color: #c3e6cb;
}
.table-hover .table-success:hover {
background-color: #b1dfbb;
}
.table-hover .table-success:hover > td,
.table-hover .table-success:hover > th {
background-color: #b1dfbb;
}
.table-info,
.table-info > th,
.table-info > td {
background-color: #bee5eb;
}
.table-hover .table-info:hover {
background-color: #abdde5;
}
.table-hover .table-info:hover > td,
.table-hover .table-info:hover > th {
background-color: #abdde5;
}
.table-warning,
.table-warning > th,
.table-warning > td {
background-color: #ffeeba;
}
.table-hover .table-warning:hover {
background-color: #ffe8a1;
}
.table-hover .table-warning:hover > td,
.table-hover .table-warning:hover > th {
background-color: #ffe8a1;
}
.table-danger,
.table-danger > th,
.table-danger > td {
background-color: #f5c6cb;
}
.table-hover .table-danger:hover {
background-color: #f1b0b7;
}
.table-hover .table-danger:hover > td,
.table-hover .table-danger:hover > th {
background-color: #f1b0b7;
}
.table-light,
.table-light > th,
.table-light > td {
background-color: #fdfdfe;
}
.table-hover .table-light:hover {
background-color: #ececf6;
}
.table-hover .table-light:hover > td,
.table-hover .table-light:hover > th {
background-color: #ececf6;
}
.table-dark,
.table-dark > th,
.table-dark > td {
background-color: #c6c8ca;
}
.table-hover .table-dark:hover {
background-color: #b9bbbe;
}
.table-hover .table-dark:hover > td,
.table-hover .table-dark:hover > th {
background-color: #b9bbbe;
}
.table-active,
.table-active > th,
.table-active > td {
background-color: rgba(0, 0, 0, 0.075);
}
.table-hover .table-active:hover {
background-color: rgba(0, 0, 0, 0.075);
}
.table-hover .table-active:hover > td,
.table-hover .table-active:hover > th {
background-color: rgba(0, 0, 0, 0.075);
}
.table .thead-dark th {
color: #fff;
background-color: #212529;
border-color: #32383e;
}
.table .thead-light th {
color: #495057;
background-color: #e9ecef;
border-color: #dee2e6;
}
.table-dark {
color: #fff;
background-color: #212529;
}
.table-dark th,
.table-dark td,
.table-dark thead th {
border-color: #32383e;
}
.table-dark.table-bordered {
border: 0;
}
.table-dark.table-striped tbody tr:nth-of-type(odd) {
background-color: rgba(255, 255, 255, 0.05);
}
.table-dark.table-hover tbody tr:hover {
background-color: rgba(255, 255, 255, 0.075);
}
@media (max-width: 575.98px) {
.table-responsive-sm {
display: block;
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.table-responsive-sm > .table-bordered {
border: 0;
}
}
@media (max-width: 767.98px) {
.table-responsive-md {
display: block;
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.table-responsive-md > .table-bordered {
border: 0;
}
}
@media (max-width: 991.98px) {
.table-responsive-lg {
display: block;
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.table-responsive-lg > .table-bordered {
border: 0;
}
}
@media (max-width: 1199.98px) {
.table-responsive-xl {
display: block;
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.table-responsive-xl > .table-bordered {
border: 0;
}
}
.table-responsive {
display: block;
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
.table-responsive > .table-bordered {
border: 0;
}
.form-control {
display: block;
width: 100%;
padding: 0.375rem 0.75rem;
font-size: 1rem;
line-height: 1.5;
color: #495057;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: 0.25rem;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.form-control::-ms-expand {
background-color: transparent;
border: 0;
}
.form-control:focus {
color: #495057;
background-color: #fff;
border-color: #80bdff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.form-control::-webkit-input-placeholder {
color: #6c757d;
opacity: 1;
}
.form-control::-moz-placeholder {
color: #6c757d;
opacity: 1;
}
.form-control:-ms-input-placeholder {
color: #6c757d;
opacity: 1;
}
.form-control::-ms-input-placeholder {
color: #6c757d;
opacity: 1;
}
.form-control::placeholder {
color: #6c757d;
opacity: 1;
}
.form-control:disabled, .form-control[readonly] {
background-color: #e9ecef;
opacity: 1;
}
select.form-control:not([size]):not([multiple]) {
height: calc(2.25rem + 2px);
}
select.form-control:focus::-ms-value {
color: #495057;
background-color: #fff;
}
.form-control-file,
.form-control-range {
display: block;
width: 100%;
}
.col-form-label {
padding-top: calc(0.375rem + 1px);
padding-bottom: calc(0.375rem + 1px);
margin-bottom: 0;
font-size: inherit;
line-height: 1.5;
}
.col-form-label-lg {
padding-top: calc(0.5rem + 1px);
padding-bottom: calc(0.5rem + 1px);
font-size: 1.25rem;
line-height: 1.5;
}
.col-form-label-sm {
padding-top: calc(0.25rem + 1px);
padding-bottom: calc(0.25rem + 1px);
font-size: 0.875rem;
line-height: 1.5;
}
.form-control-plaintext {
display: block;
width: 100%;
padding-top: 0.375rem;
padding-bottom: 0.375rem;
margin-bottom: 0;
line-height: 1.5;
background-color: transparent;
border: solid transparent;
border-width: 1px 0;
}
.form-control-plaintext.form-control-sm, .input-group-sm > .form-control-plaintext.form-control,
.input-group-sm > .input-group-prepend > .form-control-plaintext.input-group-text,
.input-group-sm > .input-group-append > .form-control-plaintext.input-group-text,
.input-group-sm > .input-group-prepend > .form-control-plaintext.btn,
.input-group-sm > .input-group-append > .form-control-plaintext.btn, .form-control-plaintext.form-control-lg, .input-group-lg > .form-control-plaintext.form-control,
.input-group-lg > .input-group-prepend > .form-control-plaintext.input-group-text,
.input-group-lg > .input-group-append > .form-control-plaintext.input-group-text,
.input-group-lg > .input-group-prepend > .form-control-plaintext.btn,
.input-group-lg > .input-group-append > .form-control-plaintext.btn {
padding-right: 0;
padding-left: 0;
}
.form-control-sm, .input-group-sm > .form-control,
.input-group-sm > .input-group-prepend > .input-group-text,
.input-group-sm > .input-group-append > .input-group-text,
.input-group-sm > .input-group-prepend > .btn,
.input-group-sm > .input-group-append > .btn {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
line-height: 1.5;
border-radius: 0.2rem;
}
select.form-control-sm:not([size]):not([multiple]), .input-group-sm > select.form-control:not([size]):not([multiple]),
.input-group-sm > .input-group-prepend > select.input-group-text:not([size]):not([multiple]),
.input-group-sm > .input-group-append > select.input-group-text:not([size]):not([multiple]),
.input-group-sm > .input-group-prepend > select.btn:not([size]):not([multiple]),
.input-group-sm > .input-group-append > select.btn:not([size]):not([multiple]) {
height: calc(1.8125rem + 2px);
}
.form-control-lg, .input-group-lg > .form-control,
.input-group-lg > .input-group-prepend > .input-group-text,
.input-group-lg > .input-group-append > .input-group-text,
.input-group-lg > .input-group-prepend > .btn,
.input-group-lg > .input-group-append > .btn {
padding: 0.5rem 1rem;
font-size: 1.25rem;
line-height: 1.5;
border-radius: 0.3rem;
}
select.form-control-lg:not([size]):not([multiple]), .input-group-lg > select.form-control:not([size]):not([multiple]),
.input-group-lg > .input-group-prepend > select.input-group-text:not([size]):not([multiple]),
.input-group-lg > .input-group-append > select.input-group-text:not([size]):not([multiple]),
.input-group-lg > .input-group-prepend > select.btn:not([size]):not([multiple]),
.input-group-lg > .input-group-append > select.btn:not([size]):not([multiple]) {
height: calc(2.875rem + 2px);
}
.form-group {
margin-bottom: 1rem;
}
.form-text {
display: block;
margin-top: 0.25rem;
}
.form-row {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-right: -5px;
margin-left: -5px;
}
.form-row > .col,
.form-row > [class*="col-"] {
padding-right: 5px;
padding-left: 5px;
}
.form-check {
position: relative;
display: block;
padding-left: 1.25rem;
}
.form-check-input {
position: absolute;
margin-top: 0.3rem;
margin-left: -1.25rem;
}
.form-check-input:disabled ~ .form-check-label {
color: #6c757d;
}
.form-check-label {
margin-bottom: 0;
}
.form-check-inline {
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
padding-left: 0;
margin-right: 0.75rem;
}
.form-check-inline .form-check-input {
position: static;
margin-top: 0;
margin-right: 0.3125rem;
margin-left: 0;
}
.valid-feedback {
display: none;
width: 100%;
margin-top: 0.25rem;
font-size: 80%;
color: #28a745;
}
.valid-tooltip {
position: absolute;
top: 100%;
z-index: 5;
display: none;
max-width: 100%;
padding: .5rem;
margin-top: .1rem;
font-size: .875rem;
line-height: 1;
color: #fff;
background-color: rgba(40, 167, 69, 0.8);
border-radius: .2rem;
}
.was-validated .form-control:valid, .form-control.is-valid, .was-validated
.custom-select:valid,
.custom-select.is-valid {
border-color: #28a745;
}
.was-validated .form-control:valid:focus, .form-control.is-valid:focus, .was-validated
.custom-select:valid:focus,
.custom-select.is-valid:focus {
border-color: #28a745;
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
}
.was-validated .form-control:valid ~ .valid-feedback,
.was-validated .form-control:valid ~ .valid-tooltip, .form-control.is-valid ~ .valid-feedback,
.form-control.is-valid ~ .valid-tooltip, .was-validated
.custom-select:valid ~ .valid-feedback,
.was-validated
.custom-select:valid ~ .valid-tooltip,
.custom-select.is-valid ~ .valid-feedback,
.custom-select.is-valid ~ .valid-tooltip {
display: block;
}
.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label {
color: #28a745;
}
.was-validated .form-check-input:valid ~ .valid-feedback,
.was-validated .form-check-input:valid ~ .valid-tooltip, .form-check-input.is-valid ~ .valid-feedback,
.form-check-input.is-valid ~ .valid-tooltip {
display: block;
}
.was-validated .custom-control-input:valid ~ .custom-control-label, .custom-control-input.is-valid ~ .custom-control-label {
color: #28a745;
}
.was-validated .custom-control-input:valid ~ .custom-control-label::before, .custom-control-input.is-valid ~ .custom-control-label::before {
background-color: #71dd8a;
}
.was-validated .custom-control-input:valid ~ .valid-feedback,
.was-validated .custom-control-input:valid ~ .valid-tooltip, .custom-control-input.is-valid ~ .valid-feedback,
.custom-control-input.is-valid ~ .valid-tooltip {
display: block;
}
.was-validated .custom-control-input:valid:checked ~ .custom-control-label::before, .custom-control-input.is-valid:checked ~ .custom-control-label::before {
background-color: #34ce57;
}
.was-validated .custom-control-input:valid:focus ~ .custom-control-label::before, .custom-control-input.is-valid:focus ~ .custom-control-label::before {
box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
}
.was-validated .custom-file-input:valid ~ .custom-file-label, .custom-file-input.is-valid ~ .custom-file-label {
border-color: #28a745;
}
.was-validated .custom-file-input:valid ~ .custom-file-label::before, .custom-file-input.is-valid ~ .custom-file-label::before {
border-color: inherit;
}
.was-validated .custom-file-input:valid ~ .valid-feedback,
.was-validated .custom-file-input:valid ~ .valid-tooltip, .custom-file-input.is-valid ~ .valid-feedback,
.custom-file-input.is-valid ~ .valid-tooltip {
display: block;
}
.was-validated .custom-file-input:valid:focus ~ .custom-file-label, .custom-file-input.is-valid:focus ~ .custom-file-label {
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
}
.invalid-feedback {
display: none;
width: 100%;
margin-top: 0.25rem;
font-size: 80%;
color: #dc3545;
}
.invalid-tooltip {
position: absolute;
top: 100%;
z-index: 5;
display: none;
max-width: 100%;
padding: .5rem;
margin-top: .1rem;
font-size: .875rem;
line-height: 1;
color: #fff;
background-color: rgba(220, 53, 69, 0.8);
border-radius: .2rem;
}
.was-validated .form-control:invalid, .form-control.is-invalid, .was-validated
.custom-select:invalid,
.custom-select.is-invalid {
border-color: #dc3545;
}
.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus, .was-validated
.custom-select:invalid:focus,
.custom-select.is-invalid:focus {
border-color: #dc3545;
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
.was-validated .form-control:invalid ~ .invalid-feedback,
.was-validated .form-control:invalid ~ .invalid-tooltip, .form-control.is-invalid ~ .invalid-feedback,
.form-control.is-invalid ~ .invalid-tooltip, .was-validated
.custom-select:invalid ~ .invalid-feedback,
.was-validated
.custom-select:invalid ~ .invalid-tooltip,
.custom-select.is-invalid ~ .invalid-feedback,
.custom-select.is-invalid ~ .invalid-tooltip {
display: block;
}
.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label {
color: #dc3545;
}
.was-validated .form-check-input:invalid ~ .invalid-feedback,
.was-validated .form-check-input:invalid ~ .invalid-tooltip, .form-check-input.is-invalid ~ .invalid-feedback,
.form-check-input.is-invalid ~ .invalid-tooltip {
display: block;
}
.was-validated .custom-control-input:invalid ~ .custom-control-label, .custom-control-input.is-invalid ~ .custom-control-label {
color: #dc3545;
}
.was-validated .custom-control-input:invalid ~ .custom-control-label::before, .custom-control-input.is-invalid ~ .custom-control-label::before {
background-color: #efa2a9;
}
.was-validated .custom-control-input:invalid ~ .invalid-feedback,
.was-validated .custom-control-input:invalid ~ .invalid-tooltip, .custom-control-input.is-invalid ~ .invalid-feedback,
.custom-control-input.is-invalid ~ .invalid-tooltip {
display: block;
}
.was-validated .custom-control-input:invalid:checked ~ .custom-control-label::before, .custom-control-input.is-invalid:checked ~ .custom-control-label::before {
background-color: #e4606d;
}
.was-validated .custom-control-input:invalid:focus ~ .custom-control-label::before, .custom-control-input.is-invalid:focus ~ .custom-control-label::before {
box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
.was-validated .custom-file-input:invalid ~ .custom-file-label, .custom-file-input.is-invalid ~ .custom-file-label {
border-color: #dc3545;
}
.was-validated .custom-file-input:invalid ~ .custom-file-label::before, .custom-file-input.is-invalid ~ .custom-file-label::before {
border-color: inherit;
}
.was-validated .custom-file-input:invalid ~ .invalid-feedback,
.was-validated .custom-file-input:invalid ~ .invalid-tooltip, .custom-file-input.is-invalid ~ .invalid-feedback,
.custom-file-input.is-invalid ~ .invalid-tooltip {
display: block;
}
.was-validated .custom-file-input:invalid:focus ~ .custom-file-label, .custom-file-input.is-invalid:focus ~ .custom-file-label {
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
.form-inline {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.form-inline .form-check {
width: 100%;
}
@media (min-width: 576px) {
.form-inline label {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
margin-bottom: 0;
}
.form-inline .form-group {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-flex: 0;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
margin-bottom: 0;
}
.form-inline .form-control {
display: inline-block;
width: auto;
vertical-align: middle;
}
.form-inline .form-control-plaintext {
display: inline-block;
}
.form-inline .input-group {
width: auto;
}
.form-inline .form-check {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
width: auto;
padding-left: 0;
}
.form-inline .form-check-input {
position: relative;
margin-top: 0;
margin-right: 0.25rem;
margin-left: 0;
}
.form-inline .custom-control {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
.form-inline .custom-control-label {
margin-bottom: 0;
}
}
.btn {
display: inline-block;
font-weight: 400;
text-align: center;
white-space: nowrap;
vertical-align: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
border: 1px solid transparent;
padding: 0.375rem 0.75rem;
font-size: 1rem;
line-height: 1.5;
border-radius: 0.25rem;
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.btn:hover, .btn:focus {
text-decoration: none;
}
.btn:focus, .btn.focus {
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.btn.disabled, .btn:disabled {
opacity: 0.65;
}
.btn:not(:disabled):not(.disabled) {
cursor: pointer;
}
.btn:not(:disabled):not(.disabled):active, .btn:not(:disabled):not(.disabled).active {
background-image: none;
}
a.btn.disabled,
fieldset:disabled a.btn {
pointer-events: none;
}
.btn-primary {
color: #fff;
background-color: #007bff;
border-color: #007bff;
}
.btn-primary:hover {
color: #fff;
background-color: #0069d9;
border-color: #0062cc;
}
.btn-primary:focus, .btn-primary.focus {
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);
}
.btn-primary.disabled, .btn-primary:disabled {
color: #fff;
background-color: #007bff;
border-color: #007bff;
}
.btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active,
.show > .btn-primary.dropdown-toggle {
color: #fff;
background-color: #0062cc;
border-color: #005cbf;
}
.btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus,
.show > .btn-primary.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);
}
.btn-secondary {
color: #fff;
background-color: #6c757d;
border-color: #6c757d;
}
.btn-secondary:hover {
color: #fff;
background-color: #5a6268;
border-color: #545b62;
}
.btn-secondary:focus, .btn-secondary.focus {
box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);
}
.btn-secondary.disabled, .btn-secondary:disabled {
color: #fff;
background-color: #6c757d;
border-color: #6c757d;
}
.btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active,
.show > .btn-secondary.dropdown-toggle {
color: #fff;
background-color: #545b62;
border-color: #4e555b;
}
.btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus,
.show > .btn-secondary.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);
}
.btn-success {
color: #fff;
background-color: #28a745;
border-color: #28a745;
}
.btn-success:hover {
color: #fff;
background-color: #218838;
border-color: #1e7e34;
}
.btn-success:focus, .btn-success.focus {
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);
}
.btn-success.disabled, .btn-success:disabled {
color: #fff;
background-color: #28a745;
border-color: #28a745;
}
.btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active,
.show > .btn-success.dropdown-toggle {
color: #fff;
background-color: #1e7e34;
border-color: #1c7430;
}
.btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus,
.show > .btn-success.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);
}
.btn-info {
color: #fff;
background-color: #17a2b8;
border-color: #17a2b8;
}
.btn-info:hover {
color: #fff;
background-color: #138496;
border-color: #117a8b;
}
.btn-info:focus, .btn-info.focus {
box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);
}
.btn-info.disabled, .btn-info:disabled {
color: #fff;
background-color: #17a2b8;
border-color: #17a2b8;
}
.btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active,
.show > .btn-info.dropdown-toggle {
color: #fff;
background-color: #117a8b;
border-color: #10707f;
}
.btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus,
.show > .btn-info.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);
}
.btn-warning {
color: #212529;
background-color: #ffc107;
border-color: #ffc107;
}
.btn-warning:hover {
color: #212529;
background-color: #e0a800;
border-color: #d39e00;
}
.btn-warning:focus, .btn-warning.focus {
box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);
}
.btn-warning.disabled, .btn-warning:disabled {
color: #212529;
background-color: #ffc107;
border-color: #ffc107;
}
.btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active,
.show > .btn-warning.dropdown-toggle {
color: #212529;
background-color: #d39e00;
border-color: #c69500;
}
.btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus,
.show > .btn-warning.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);
}
.btn-danger {
color: #fff;
background-color: #dc3545;
border-color: #dc3545;
}
.btn-danger:hover {
color: #fff;
background-color: #c82333;
border-color: #bd2130;
}
.btn-danger:focus, .btn-danger.focus {
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);
}
.btn-danger.disabled, .btn-danger:disabled {
color: #fff;
background-color: #dc3545;
border-color: #dc3545;
}
.btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active,
.show > .btn-danger.dropdown-toggle {
color: #fff;
background-color: #bd2130;
border-color: #b21f2d;
}
.btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus,
.show > .btn-danger.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);
}
.btn-light {
color: #212529;
background-color: #f8f9fa;
border-color: #f8f9fa;
}
.btn-light:hover {
color: #212529;
background-color: #e2e6ea;
border-color: #dae0e5;
}
.btn-light:focus, .btn-light.focus {
box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);
}
.btn-light.disabled, .btn-light:disabled {
color: #212529;
background-color: #f8f9fa;
border-color: #f8f9fa;
}
.btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active,
.show > .btn-light.dropdown-toggle {
color: #212529;
background-color: #dae0e5;
border-color: #d3d9df;
}
.btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus,
.show > .btn-light.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);
}
.btn-dark {
color: #fff;
background-color: #343a40;
border-color: #343a40;
}
.btn-dark:hover {
color: #fff;
background-color: #23272b;
border-color: #1d2124;
}
.btn-dark:focus, .btn-dark.focus {
box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);
}
.btn-dark.disabled, .btn-dark:disabled {
color: #fff;
background-color: #343a40;
border-color: #343a40;
}
.btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active,
.show > .btn-dark.dropdown-toggle {
color: #fff;
background-color: #1d2124;
border-color: #171a1d;
}
.btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus,
.show > .btn-dark.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);
}
.btn-outline-primary {
color: #007bff;
background-color: transparent;
background-image: none;
border-color: #007bff;
}
.btn-outline-primary:hover {
color: #fff;
background-color: #007bff;
border-color: #007bff;
}
.btn-outline-primary:focus, .btn-outline-primary.focus {
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);
}
.btn-outline-primary.disabled, .btn-outline-primary:disabled {
color: #007bff;
background-color: transparent;
}
.btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active,
.show > .btn-outline-primary.dropdown-toggle {
color: #fff;
background-color: #007bff;
border-color: #007bff;
}
.btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-primary.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);
}
.btn-outline-secondary {
color: #6c757d;
background-color: transparent;
background-image: none;
border-color: #6c757d;
}
.btn-outline-secondary:hover {
color: #fff;
background-color: #6c757d;
border-color: #6c757d;
}
.btn-outline-secondary:focus, .btn-outline-secondary.focus {
box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);
}
.btn-outline-secondary.disabled, .btn-outline-secondary:disabled {
color: #6c757d;
background-color: transparent;
}
.btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active,
.show > .btn-outline-secondary.dropdown-toggle {
color: #fff;
background-color: #6c757d;
border-color: #6c757d;
}
.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-secondary.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5);
}
.btn-outline-success {
color: #28a745;
background-color: transparent;
background-image: none;
border-color: #28a745;
}
.btn-outline-success:hover {
color: #fff;
background-color: #28a745;
border-color: #28a745;
}
.btn-outline-success:focus, .btn-outline-success.focus {
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);
}
.btn-outline-success.disabled, .btn-outline-success:disabled {
color: #28a745;
background-color: transparent;
}
.btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active,
.show > .btn-outline-success.dropdown-toggle {
color: #fff;
background-color: #28a745;
border-color: #28a745;
}
.btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-success.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5);
}
.btn-outline-info {
color: #17a2b8;
background-color: transparent;
background-image: none;
border-color: #17a2b8;
}
.btn-outline-info:hover {
color: #fff;
background-color: #17a2b8;
border-color: #17a2b8;
}
.btn-outline-info:focus, .btn-outline-info.focus {
box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);
}
.btn-outline-info.disabled, .btn-outline-info:disabled {
color: #17a2b8;
background-color: transparent;
}
.btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active,
.show > .btn-outline-info.dropdown-toggle {
color: #fff;
background-color: #17a2b8;
border-color: #17a2b8;
}
.btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-info.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5);
}
.btn-outline-warning {
color: #ffc107;
background-color: transparent;
background-image: none;
border-color: #ffc107;
}
.btn-outline-warning:hover {
color: #212529;
background-color: #ffc107;
border-color: #ffc107;
}
.btn-outline-warning:focus, .btn-outline-warning.focus {
box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);
}
.btn-outline-warning.disabled, .btn-outline-warning:disabled {
color: #ffc107;
background-color: transparent;
}
.btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active,
.show > .btn-outline-warning.dropdown-toggle {
color: #212529;
background-color: #ffc107;
border-color: #ffc107;
}
.btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-warning.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5);
}
.btn-outline-danger {
color: #dc3545;
background-color: transparent;
background-image: none;
border-color: #dc3545;
}
.btn-outline-danger:hover {
color: #fff;
background-color: #dc3545;
border-color: #dc3545;
}
.btn-outline-danger:focus, .btn-outline-danger.focus {
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);
}
.btn-outline-danger.disabled, .btn-outline-danger:disabled {
color: #dc3545;
background-color: transparent;
}
.btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active,
.show > .btn-outline-danger.dropdown-toggle {
color: #fff;
background-color: #dc3545;
border-color: #dc3545;
}
.btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-danger.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5);
}
.btn-outline-light {
color: #f8f9fa;
background-color: transparent;
background-image: none;
border-color: #f8f9fa;
}
.btn-outline-light:hover {
color: #212529;
background-color: #f8f9fa;
border-color: #f8f9fa;
}
.btn-outline-light:focus, .btn-outline-light.focus {
box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);
}
.btn-outline-light.disabled, .btn-outline-light:disabled {
color: #f8f9fa;
background-color: transparent;
}
.btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active,
.show > .btn-outline-light.dropdown-toggle {
color: #212529;
background-color: #f8f9fa;
border-color: #f8f9fa;
}
.btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-light.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5);
}
.btn-outline-dark {
color: #343a40;
background-color: transparent;
background-image: none;
border-color: #343a40;
}
.btn-outline-dark:hover {
color: #fff;
background-color: #343a40;
border-color: #343a40;
}
.btn-outline-dark:focus, .btn-outline-dark.focus {
box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);
}
.btn-outline-dark.disabled, .btn-outline-dark:disabled {
color: #343a40;
background-color: transparent;
}
.btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active,
.show > .btn-outline-dark.dropdown-toggle {
color: #fff;
background-color: #343a40;
border-color: #343a40;
}
.btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus,
.show > .btn-outline-dark.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);
}
.btn-link {
font-weight: 400;
color: #007bff;
background-color: transparent;
}
.btn-link:hover {
color: #0056b3;
text-decoration: underline;
background-color: transparent;
border-color: transparent;
}
.btn-link:focus, .btn-link.focus {
text-decoration: underline;
border-color: transparent;
box-shadow: none;
}
.btn-link:disabled, .btn-link.disabled {
color: #6c757d;
}
.btn-lg, .btn-group-lg > .btn {
padding: 0.5rem 1rem;
font-size: 1.25rem;
line-height: 1.5;
border-radius: 0.3rem;
}
.btn-sm, .btn-group-sm > .btn {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
line-height: 1.5;
border-radius: 0.2rem;
}
.btn-block {
display: block;
width: 100%;
}
.btn-block + .btn-block {
margin-top: 0.5rem;
}
input[type="submit"].btn-block,
input[type="reset"].btn-block,
input[type="button"].btn-block {
width: 100%;
}
.fade {
opacity: 0;
transition: opacity 0.15s linear;
}
.fade.show {
opacity: 1;
}
.collapse {
display: none;
}
.collapse.show {
display: block;
}
tr.collapse.show {
display: table-row;
}
tbody.collapse.show {
display: table-row-group;
}
.collapsing {
position: relative;
height: 0;
overflow: hidden;
transition: height 0.35s ease;
}
.dropup,
.dropdown {
position: relative;
}
.dropdown-toggle::after {
display: inline-block;
width: 0;
height: 0;
margin-left: 0.255em;
vertical-align: 0.255em;
content: "";
border-top: 0.3em solid;
border-right: 0.3em solid transparent;
border-bottom: 0;
border-left: 0.3em solid transparent;
}
.dropdown-toggle:empty::after {
margin-left: 0;
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
z-index: 1000;
display: none;
float: left;
min-width: 10rem;
padding: 0.5rem 0;
margin: 0.125rem 0 0;
font-size: 1rem;
color: #212529;
text-align: left;
list-style: none;
background-color: #fff;
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.15);
border-radius: 0.25rem;
}
.dropup .dropdown-menu {
margin-top: 0;
margin-bottom: 0.125rem;
}
.dropup .dropdown-toggle::after {
display: inline-block;
width: 0;
height: 0;
margin-left: 0.255em;
vertical-align: 0.255em;
content: "";
border-top: 0;
border-right: 0.3em solid transparent;
border-bottom: 0.3em solid;
border-left: 0.3em solid transparent;
}
.dropup .dropdown-toggle:empty::after {
margin-left: 0;
}
.dropright .dropdown-menu {
margin-top: 0;
margin-left: 0.125rem;
}
.dropright .dropdown-toggle::after {
display: inline-block;
width: 0;
height: 0;
margin-left: 0.255em;
vertical-align: 0.255em;
content: "";
border-top: 0.3em solid transparent;
border-bottom: 0.3em solid transparent;
border-left: 0.3em solid;
}
.dropright .dropdown-toggle:empty::after {
margin-left: 0;
}
.dropright .dropdown-toggle::after {
vertical-align: 0;
}
.dropleft .dropdown-menu {
margin-top: 0;
margin-right: 0.125rem;
}
.dropleft .dropdown-toggle::after {
display: inline-block;
width: 0;
height: 0;
margin-left: 0.255em;
vertical-align: 0.255em;
content: "";
}
.dropleft .dropdown-toggle::after {
display: none;
}
.dropleft .dropdown-toggle::before {
display: inline-block;
width: 0;
height: 0;
margin-right: 0.255em;
vertical-align: 0.255em;
content: "";
border-top: 0.3em solid transparent;
border-right: 0.3em solid;
border-bottom: 0.3em solid transparent;
}
.dropleft .dropdown-toggle:empty::after {
margin-left: 0;
}
.dropleft .dropdown-toggle::before {
vertical-align: 0;
}
.dropdown-divider {
height: 0;
margin: 0.5rem 0;
overflow: hidden;
border-top: 1px solid #e9ecef;
}
.dropdown-item {
display: block;
width: 100%;
padding: 0.25rem 1.5rem;
clear: both;
font-weight: 400;
color: #212529;
text-align: inherit;
white-space: nowrap;
background-color: transparent;
border: 0;
}
.dropdown-item:hover, .dropdown-item:focus {
color: #16181b;
text-decoration: none;
background-color: #f8f9fa;
}
.dropdown-item.active, .dropdown-item:active {
color: #fff;
text-decoration: none;
background-color: #007bff;
}
.dropdown-item.disabled, .dropdown-item:disabled {
color: #6c757d;
background-color: transparent;
}
.dropdown-menu.show {
display: block;
}
.dropdown-header {
display: block;
padding: 0.5rem 1.5rem;
margin-bottom: 0;
font-size: 0.875rem;
color: #6c757d;
white-space: nowrap;
}
.btn-group,
.btn-group-vertical {
position: relative;
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
vertical-align: middle;
}
.btn-group > .btn,
.btn-group-vertical > .btn {
position: relative;
-webkit-box-flex: 0;
-ms-flex: 0 1 auto;
flex: 0 1 auto;
}
.btn-group > .btn:hover,
.btn-group-vertical > .btn:hover {
z-index: 1;
}
.btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active,
.btn-group-vertical > .btn:focus,
.btn-group-vertical > .btn:active,
.btn-group-vertical > .btn.active {
z-index: 1;
}
.btn-group .btn + .btn,
.btn-group .btn + .btn-group,
.btn-group .btn-group + .btn,
.btn-group .btn-group + .btn-group,
.btn-group-vertical .btn + .btn,
.btn-group-vertical .btn + .btn-group,
.btn-group-vertical .btn-group + .btn,
.btn-group-vertical .btn-group + .btn-group {
margin-left: -1px;
}
.btn-toolbar {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
}
.btn-toolbar .input-group {
width: auto;
}
.btn-group > .btn:first-child {
margin-left: 0;
}
.btn-group > .btn:not(:last-child):not(.dropdown-toggle),
.btn-group > .btn-group:not(:last-child) > .btn {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.btn-group > .btn:not(:first-child),
.btn-group > .btn-group:not(:first-child) > .btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.dropdown-toggle-split {
padding-right: 0.5625rem;
padding-left: 0.5625rem;
}
.dropdown-toggle-split::after {
margin-left: 0;
}
.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {
padding-right: 0.375rem;
padding-left: 0.375rem;
}
.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {
padding-right: 0.75rem;
padding-left: 0.75rem;
}
.btn-group-vertical {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
.btn-group-vertical .btn,
.btn-group-vertical .btn-group {
width: 100%;
}
.btn-group-vertical > .btn + .btn,
.btn-group-vertical > .btn + .btn-group,
.btn-group-vertical > .btn-group + .btn,
.btn-group-vertical > .btn-group + .btn-group {
margin-top: -1px;
margin-left: 0;
}
.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),
.btn-group-vertical > .btn-group:not(:last-child) > .btn {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.btn-group-vertical > .btn:not(:first-child),
.btn-group-vertical > .btn-group:not(:first-child) > .btn {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.btn-group-toggle > .btn,
.btn-group-toggle > .btn-group > .btn {
margin-bottom: 0;
}
.btn-group-toggle > .btn input[type="radio"],
.btn-group-toggle > .btn input[type="checkbox"],
.btn-group-toggle > .btn-group > .btn input[type="radio"],
.btn-group-toggle > .btn-group > .btn input[type="checkbox"] {
position: absolute;
clip: rect(0, 0, 0, 0);
pointer-events: none;
}
.input-group {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-align: stretch;
-ms-flex-align: stretch;
align-items: stretch;
width: 100%;
}
.input-group > .form-control,
.input-group > .custom-select,
.input-group > .custom-file {
position: relative;
-webkit-box-flex: 1;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
width: 1%;
margin-bottom: 0;
}
.input-group > .form-control:focus,
.input-group > .custom-select:focus,
.input-group > .custom-file:focus {
z-index: 3;
}
.input-group > .form-control + .form-control,
.input-group > .form-control + .custom-select,
.input-group > .form-control + .custom-file,
.input-group > .custom-select + .form-control,
.input-group > .custom-select + .custom-select,
.input-group > .custom-select + .custom-file,
.input-group > .custom-file + .form-control,
.input-group > .custom-file + .custom-select,
.input-group > .custom-file + .custom-file {
margin-left: -1px;
}
.input-group > .form-control:not(:last-child),
.input-group > .custom-select:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group > .form-control:not(:first-child),
.input-group > .custom-select:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.input-group > .custom-file {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.input-group > .custom-file:not(:last-child) .custom-file-label,
.input-group > .custom-file:not(:last-child) .custom-file-label::before {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group > .custom-file:not(:first-child) .custom-file-label,
.input-group > .custom-file:not(:first-child) .custom-file-label::before {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.input-group-prepend,
.input-group-append {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.input-group-prepend .btn,
.input-group-append .btn {
position: relative;
z-index: 2;
}
.input-group-prepend .btn + .btn,
.input-group-prepend .btn + .input-group-text,
.input-group-prepend .input-group-text + .input-group-text,
.input-group-prepend .input-group-text + .btn,
.input-group-append .btn + .btn,
.input-group-append .btn + .input-group-text,
.input-group-append .input-group-text + .input-group-text,
.input-group-append .input-group-text + .btn {
margin-left: -1px;
}
.input-group-prepend {
margin-right: -1px;
}
.input-group-append {
margin-left: -1px;
}
.input-group-text {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
padding: 0.375rem 0.75rem;
margin-bottom: 0;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #495057;
text-align: center;
white-space: nowrap;
background-color: #e9ecef;
border: 1px solid #ced4da;
border-radius: 0.25rem;
}
.input-group-text input[type="radio"],
.input-group-text input[type="checkbox"] {
margin-top: 0;
}
.input-group > .input-group-prepend > .btn,
.input-group > .input-group-prepend > .input-group-text,
.input-group > .input-group-append:not(:last-child) > .btn,
.input-group > .input-group-append:not(:last-child) > .input-group-text,
.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle),
.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group > .input-group-append > .btn,
.input-group > .input-group-append > .input-group-text,
.input-group > .input-group-prepend:not(:first-child) > .btn,
.input-group > .input-group-prepend:not(:first-child) > .input-group-text,
.input-group > .input-group-prepend:first-child > .btn:not(:first-child),
.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.custom-control {
position: relative;
display: block;
min-height: 1.5rem;
padding-left: 1.5rem;
}
.custom-control-inline {
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
margin-right: 1rem;
}
.custom-control-input {
position: absolute;
z-index: -1;
opacity: 0;
}
.custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
background-color: #007bff;
}
.custom-control-input:focus ~ .custom-control-label::before {
box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.custom-control-input:active ~ .custom-control-label::before {
color: #fff;
background-color: #b3d7ff;
}
.custom-control-input:disabled ~ .custom-control-label {
color: #6c757d;
}
.custom-control-input:disabled ~ .custom-control-label::before {
background-color: #e9ecef;
}
.custom-control-label {
margin-bottom: 0;
}
.custom-control-label::before {
position: absolute;
top: 0.25rem;
left: 0;
display: block;
width: 1rem;
height: 1rem;
pointer-events: none;
content: "";
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-color: #dee2e6;
}
.custom-control-label::after {
position: absolute;
top: 0.25rem;
left: 0;
display: block;
width: 1rem;
height: 1rem;
content: "";
background-repeat: no-repeat;
background-position: center center;
background-size: 50% 50%;
}
.custom-checkbox .custom-control-label::before {
border-radius: 0.25rem;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before {
background-color: #007bff;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::after {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E");
}
.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before {
background-color: #007bff;
}
.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::after {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E");
}
.custom-checkbox .custom-control-input:disabled:checked ~ .custom-control-label::before {
background-color: rgba(0, 123, 255, 0.5);
}
.custom-checkbox .custom-control-input:disabled:indeterminate ~ .custom-control-label::before {
background-color: rgba(0, 123, 255, 0.5);
}
.custom-radio .custom-control-label::before {
border-radius: 50%;
}
.custom-radio .custom-control-input:checked ~ .custom-control-label::before {
background-color: #007bff;
}
.custom-radio .custom-control-input:checked ~ .custom-control-label::after {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E");
}
.custom-radio .custom-control-input:disabled:checked ~ .custom-control-label::before {
background-color: rgba(0, 123, 255, 0.5);
}
.custom-select {
display: inline-block;
width: 100%;
height: calc(2.25rem + 2px);
padding: 0.375rem 1.75rem 0.375rem 0.75rem;
line-height: 1.5;
color: #495057;
vertical-align: middle;
background: #fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat right 0.75rem center;
background-size: 8px 10px;
border: 1px solid #ced4da;
border-radius: 0.25rem;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.custom-select:focus {
border-color: #80bdff;
outline: 0;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075), 0 0 5px rgba(128, 189, 255, 0.5);
}
.custom-select:focus::-ms-value {
color: #495057;
background-color: #fff;
}
.custom-select[multiple], .custom-select[size]:not([size="1"]) {
height: auto;
padding-right: 0.75rem;
background-image: none;
}
.custom-select:disabled {
color: #6c757d;
background-color: #e9ecef;
}
.custom-select::-ms-expand {
opacity: 0;
}
.custom-select-sm {
height: calc(1.8125rem + 2px);
padding-top: 0.375rem;
padding-bottom: 0.375rem;
font-size: 75%;
}
.custom-select-lg {
height: calc(2.875rem + 2px);
padding-top: 0.375rem;
padding-bottom: 0.375rem;
font-size: 125%;
}
.custom-file {
position: relative;
display: inline-block;
width: 100%;
height: calc(2.25rem + 2px);
margin-bottom: 0;
}
.custom-file-input {
position: relative;
z-index: 2;
width: 100%;
height: calc(2.25rem + 2px);
margin: 0;
opacity: 0;
}
.custom-file-input:focus ~ .custom-file-control {
border-color: #80bdff;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.custom-file-input:focus ~ .custom-file-control::before {
border-color: #80bdff;
}
.custom-file-input:lang(en) ~ .custom-file-label::after {
content: "Browse";
}
.custom-file-label {
position: absolute;
top: 0;
right: 0;
left: 0;
z-index: 1;
height: calc(2.25rem + 2px);
padding: 0.375rem 0.75rem;
line-height: 1.5;
color: #495057;
background-color: #fff;
border: 1px solid #ced4da;
border-radius: 0.25rem;
}
.custom-file-label::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
z-index: 3;
display: block;
height: calc(calc(2.25rem + 2px) - 1px * 2);
padding: 0.375rem 0.75rem;
line-height: 1.5;
color: #495057;
content: "Browse";
background-color: #e9ecef;
border-left: 1px solid #ced4da;
border-radius: 0 0.25rem 0.25rem 0;
}
.nav {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
padding-left: 0;
margin-bottom: 0;
list-style: none;
}
.nav-link {
display: block;
padding: 0.5rem 1rem;
}
.nav-link:hover, .nav-link:focus {
text-decoration: none;
}
.nav-link.disabled {
color: #6c757d;
}
.nav-tabs {
border-bottom: 1px solid #dee2e6;
}
.nav-tabs .nav-item {
margin-bottom: -1px;
}
.nav-tabs .nav-link {
border: 1px solid transparent;
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
}
.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {
border-color: #e9ecef #e9ecef #dee2e6;
}
.nav-tabs .nav-link.disabled {
color: #6c757d;
background-color: transparent;
border-color: transparent;
}
.nav-tabs .nav-link.active,
.nav-tabs .nav-item.show .nav-link {
color: #495057;
background-color: #fff;
border-color: #dee2e6 #dee2e6 #fff;
}
.nav-tabs .dropdown-menu {
margin-top: -1px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.nav-pills .nav-link {
border-radius: 0.25rem;
}
.nav-pills .nav-link.active,
.nav-pills .show > .nav-link {
color: #fff;
background-color: #007bff;
}
.nav-fill .nav-item {
-webkit-box-flex: 1;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
text-align: center;
}
.nav-justified .nav-item {
-ms-flex-preferred-size: 0;
flex-basis: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
text-align: center;
}
.tab-content > .tab-pane {
display: none;
}
.tab-content > .active {
display: block;
}
.navbar {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
padding: 0.5rem 1rem;
}
.navbar > .container,
.navbar > .container-fluid {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
}
.navbar-brand {
display: inline-block;
padding-top: 0.3125rem;
padding-bottom: 0.3125rem;
margin-right: 1rem;
font-size: 1.25rem;
line-height: inherit;
white-space: nowrap;
}
.navbar-brand:hover, .navbar-brand:focus {
text-decoration: none;
}
.navbar-nav {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
padding-left: 0;
margin-bottom: 0;
list-style: none;
}
.navbar-nav .nav-link {
padding-right: 0;
padding-left: 0;
}
.navbar-nav .dropdown-menu {
position: static;
float: none;
}
.navbar-text {
display: inline-block;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
.navbar-collapse {
-ms-flex-preferred-size: 100%;
flex-basis: 100%;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.navbar-toggler {
padding: 0.25rem 0.75rem;
font-size: 1.25rem;
line-height: 1;
background-color: transparent;
border: 1px solid transparent;
border-radius: 0.25rem;
}
.navbar-toggler:hover, .navbar-toggler:focus {
text-decoration: none;
}
.navbar-toggler:not(:disabled):not(.disabled) {
cursor: pointer;
}
.navbar-toggler-icon {
display: inline-block;
width: 1.5em;
height: 1.5em;
vertical-align: middle;
content: "";
background: no-repeat center center;
background-size: 100% 100%;
}
@media (max-width: 575.98px) {
.navbar-expand-sm > .container,
.navbar-expand-sm > .container-fluid {
padding-right: 0;
padding-left: 0;
}
}
@media (min-width: 576px) {
.navbar-expand-sm {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row nowrap;
flex-flow: row nowrap;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
}
.navbar-expand-sm .navbar-nav {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
}
.navbar-expand-sm .navbar-nav .dropdown-menu {
position: absolute;
}
.navbar-expand-sm .navbar-nav .dropdown-menu-right {
right: 0;
left: auto;
}
.navbar-expand-sm .navbar-nav .nav-link {
padding-right: 0.5rem;
padding-left: 0.5rem;
}
.navbar-expand-sm > .container,
.navbar-expand-sm > .container-fluid {
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
}
.navbar-expand-sm .navbar-collapse {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
-ms-flex-preferred-size: auto;
flex-basis: auto;
}
.navbar-expand-sm .navbar-toggler {
display: none;
}
.navbar-expand-sm .dropup .dropdown-menu {
top: auto;
bottom: 100%;
}
}
@media (max-width: 767.98px) {
.navbar-expand-md > .container,
.navbar-expand-md > .container-fluid {
padding-right: 0;
padding-left: 0;
}
}
@media (min-width: 768px) {
.navbar-expand-md {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row nowrap;
flex-flow: row nowrap;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
}
.navbar-expand-md .navbar-nav {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
}
.navbar-expand-md .navbar-nav .dropdown-menu {
position: absolute;
}
.navbar-expand-md .navbar-nav .dropdown-menu-right {
right: 0;
left: auto;
}
.navbar-expand-md .navbar-nav .nav-link {
padding-right: 0.5rem;
padding-left: 0.5rem;
}
.navbar-expand-md > .container,
.navbar-expand-md > .container-fluid {
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
}
.navbar-expand-md .navbar-collapse {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
-ms-flex-preferred-size: auto;
flex-basis: auto;
}
.navbar-expand-md .navbar-toggler {
display: none;
}
.navbar-expand-md .dropup .dropdown-menu {
top: auto;
bottom: 100%;
}
}
@media (max-width: 991.98px) {
.navbar-expand-lg > .container,
.navbar-expand-lg > .container-fluid {
padding-right: 0;
padding-left: 0;
}
}
@media (min-width: 992px) {
.navbar-expand-lg {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row nowrap;
flex-flow: row nowrap;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
}
.navbar-expand-lg .navbar-nav {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
}
.navbar-expand-lg .navbar-nav .dropdown-menu {
position: absolute;
}
.navbar-expand-lg .navbar-nav .dropdown-menu-right {
right: 0;
left: auto;
}
.navbar-expand-lg .navbar-nav .nav-link {
padding-right: 0.5rem;
padding-left: 0.5rem;
}
.navbar-expand-lg > .container,
.navbar-expand-lg > .container-fluid {
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
}
.navbar-expand-lg .navbar-collapse {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
-ms-flex-preferred-size: auto;
flex-basis: auto;
}
.navbar-expand-lg .navbar-toggler {
display: none;
}
.navbar-expand-lg .dropup .dropdown-menu {
top: auto;
bottom: 100%;
}
}
@media (max-width: 1199.98px) {
.navbar-expand-xl > .container,
.navbar-expand-xl > .container-fluid {
padding-right: 0;
padding-left: 0;
}
}
@media (min-width: 1200px) {
.navbar-expand-xl {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row nowrap;
flex-flow: row nowrap;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
}
.navbar-expand-xl .navbar-nav {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
}
.navbar-expand-xl .navbar-nav .dropdown-menu {
position: absolute;
}
.navbar-expand-xl .navbar-nav .dropdown-menu-right {
right: 0;
left: auto;
}
.navbar-expand-xl .navbar-nav .nav-link {
padding-right: 0.5rem;
padding-left: 0.5rem;
}
.navbar-expand-xl > .container,
.navbar-expand-xl > .container-fluid {
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
}
.navbar-expand-xl .navbar-collapse {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
-ms-flex-preferred-size: auto;
flex-basis: auto;
}
.navbar-expand-xl .navbar-toggler {
display: none;
}
.navbar-expand-xl .dropup .dropdown-menu {
top: auto;
bottom: 100%;
}
}
.navbar-expand {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row nowrap;
flex-flow: row nowrap;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
}
.navbar-expand > .container,
.navbar-expand > .container-fluid {
padding-right: 0;
padding-left: 0;
}
.navbar-expand .navbar-nav {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
}
.navbar-expand .navbar-nav .dropdown-menu {
position: absolute;
}
.navbar-expand .navbar-nav .dropdown-menu-right {
right: 0;
left: auto;
}
.navbar-expand .navbar-nav .nav-link {
padding-right: 0.5rem;
padding-left: 0.5rem;
}
.navbar-expand > .container,
.navbar-expand > .container-fluid {
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
}
.navbar-expand .navbar-collapse {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
-ms-flex-preferred-size: auto;
flex-basis: auto;
}
.navbar-expand .navbar-toggler {
display: none;
}
.navbar-expand .dropup .dropdown-menu {
top: auto;
bottom: 100%;
}
.navbar-light .navbar-brand {
color: rgba(0, 0, 0, 0.9);
}
.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus {
color: rgba(0, 0, 0, 0.9);
}
.navbar-light .navbar-nav .nav-link {
color: rgba(0, 0, 0, 0.5);
}
.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus {
color: rgba(0, 0, 0, 0.7);
}
.navbar-light .navbar-nav .nav-link.disabled {
color: rgba(0, 0, 0, 0.3);
}
.navbar-light .navbar-nav .show > .nav-link,
.navbar-light .navbar-nav .active > .nav-link,
.navbar-light .navbar-nav .nav-link.show,
.navbar-light .navbar-nav .nav-link.active {
color: rgba(0, 0, 0, 0.9);
}
.navbar-light .navbar-toggler {
color: rgba(0, 0, 0, 0.5);
border-color: rgba(0, 0, 0, 0.1);
}
.navbar-light .navbar-toggler-icon {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E");
}
.navbar-light .navbar-text {
color: rgba(0, 0, 0, 0.5);
}
.navbar-light .navbar-text a {
color: rgba(0, 0, 0, 0.9);
}
.navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus {
color: rgba(0, 0, 0, 0.9);
}
.navbar-dark .navbar-brand {
color: #fff;
}
.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus {
color: #fff;
}
.navbar-dark .navbar-nav .nav-link {
color: rgba(255, 255, 255, 0.5);
}
.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus {
color: rgba(255, 255, 255, 0.75);
}
.navbar-dark .navbar-nav .nav-link.disabled {
color: rgba(255, 255, 255, 0.25);
}
.navbar-dark .navbar-nav .show > .nav-link,
.navbar-dark .navbar-nav .active > .nav-link,
.navbar-dark .navbar-nav .nav-link.show,
.navbar-dark .navbar-nav .nav-link.active {
color: #fff;
}
.navbar-dark .navbar-toggler {
color: rgba(255, 255, 255, 0.5);
border-color: rgba(255, 255, 255, 0.1);
}
.navbar-dark .navbar-toggler-icon {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E");
}
.navbar-dark .navbar-text {
color: rgba(255, 255, 255, 0.5);
}
.navbar-dark .navbar-text a {
color: #fff;
}
.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus {
color: #fff;
}
.card {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border: 1px solid rgba(0, 0, 0, 0.125);
border-radius: 0.25rem;
}
.card > hr {
margin-right: 0;
margin-left: 0;
}
.card > .list-group:first-child .list-group-item:first-child {
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
}
.card > .list-group:last-child .list-group-item:last-child {
border-bottom-right-radius: 0.25rem;
border-bottom-left-radius: 0.25rem;
}
.card-body {
-webkit-box-flex: 1;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
padding: 1.25rem;
}
.card-title {
margin-bottom: 0.75rem;
}
.card-subtitle {
margin-top: -0.375rem;
margin-bottom: 0;
}
.card-text:last-child {
margin-bottom: 0;
}
.card-link:hover {
text-decoration: none;
}
.card-link + .card-link {
margin-left: 1.25rem;
}
.card-header {
padding: 0.75rem 1.25rem;
margin-bottom: 0;
background-color: rgba(0, 0, 0, 0.03);
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
}
.card-header:first-child {
border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0;
}
.card-header + .list-group .list-group-item:first-child {
border-top: 0;
}
.card-footer {
padding: 0.75rem 1.25rem;
background-color: rgba(0, 0, 0, 0.03);
border-top: 1px solid rgba(0, 0, 0, 0.125);
}
.card-footer:last-child {
border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px);
}
.card-header-tabs {
margin-right: -0.625rem;
margin-bottom: -0.75rem;
margin-left: -0.625rem;
border-bottom: 0;
}
.card-header-pills {
margin-right: -0.625rem;
margin-left: -0.625rem;
}
.card-img-overlay {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 1.25rem;
}
.card-img {
width: 100%;
border-radius: calc(0.25rem - 1px);
}
.card-img-top {
width: 100%;
border-top-left-radius: calc(0.25rem - 1px);
border-top-right-radius: calc(0.25rem - 1px);
}
.card-img-bottom {
width: 100%;
border-bottom-right-radius: calc(0.25rem - 1px);
border-bottom-left-radius: calc(0.25rem - 1px);
}
.card-deck {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.card-deck .card {
margin-bottom: 15px;
}
@media (min-width: 576px) {
.card-deck {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
margin-right: -15px;
margin-left: -15px;
}
.card-deck .card {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-flex: 1;
-ms-flex: 1 0 0%;
flex: 1 0 0%;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
margin-right: 15px;
margin-bottom: 0;
margin-left: 15px;
}
}
.card-group {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.card-group > .card {
margin-bottom: 15px;
}
@media (min-width: 576px) {
.card-group {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
}
.card-group > .card {
-webkit-box-flex: 1;
-ms-flex: 1 0 0%;
flex: 1 0 0%;
margin-bottom: 0;
}
.card-group > .card + .card {
margin-left: 0;
border-left: 0;
}
.card-group > .card:first-child {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.card-group > .card:first-child .card-img-top,
.card-group > .card:first-child .card-header {
border-top-right-radius: 0;
}
.card-group > .card:first-child .card-img-bottom,
.card-group > .card:first-child .card-footer {
border-bottom-right-radius: 0;
}
.card-group > .card:last-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.card-group > .card:last-child .card-img-top,
.card-group > .card:last-child .card-header {
border-top-left-radius: 0;
}
.card-group > .card:last-child .card-img-bottom,
.card-group > .card:last-child .card-footer {
border-bottom-left-radius: 0;
}
.card-group > .card:only-child {
border-radius: 0.25rem;
}
.card-group > .card:only-child .card-img-top,
.card-group > .card:only-child .card-header {
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
}
.card-group > .card:only-child .card-img-bottom,
.card-group > .card:only-child .card-footer {
border-bottom-right-radius: 0.25rem;
border-bottom-left-radius: 0.25rem;
}
.card-group > .card:not(:first-child):not(:last-child):not(:only-child) {
border-radius: 0;
}
.card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-img-top,
.card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,
.card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-header,
.card-group > .card:not(:first-child):not(:last-child):not(:only-child) .card-footer {
border-radius: 0;
}
}
.card-columns .card {
margin-bottom: 0.75rem;
}
@media (min-width: 576px) {
.card-columns {
-webkit-column-count: 3;
-moz-column-count: 3;
column-count: 3;
-webkit-column-gap: 1.25rem;
-moz-column-gap: 1.25rem;
column-gap: 1.25rem;
}
.card-columns .card {
display: inline-block;
width: 100%;
}
}
.breadcrumb {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
padding: 0.75rem 1rem;
margin-bottom: 1rem;
list-style: none;
background-color: #e9ecef;
border-radius: 0.25rem;
}
.breadcrumb-item + .breadcrumb-item::before {
display: inline-block;
padding-right: 0.5rem;
padding-left: 0.5rem;
color: #6c757d;
content: "/";
}
.breadcrumb-item + .breadcrumb-item:hover::before {
text-decoration: underline;
}
.breadcrumb-item + .breadcrumb-item:hover::before {
text-decoration: none;
}
.breadcrumb-item.active {
color: #6c757d;
}
.pagination {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
padding-left: 0;
list-style: none;
border-radius: 0.25rem;
}
.page-link {
position: relative;
display: block;
padding: 0.5rem 0.75rem;
margin-left: -1px;
line-height: 1.25;
color: #007bff;
background-color: #fff;
border: 1px solid #dee2e6;
}
.page-link:hover {
color: #0056b3;
text-decoration: none;
background-color: #e9ecef;
border-color: #dee2e6;
}
.page-link:focus {
z-index: 2;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.page-link:not(:disabled):not(.disabled) {
cursor: pointer;
}
.page-item:first-child .page-link {
margin-left: 0;
border-top-left-radius: 0.25rem;
border-bottom-left-radius: 0.25rem;
}
.page-item:last-child .page-link {
border-top-right-radius: 0.25rem;
border-bottom-right-radius: 0.25rem;
}
.page-item.active .page-link {
z-index: 1;
color: #fff;
background-color: #007bff;
border-color: #007bff;
}
.page-item.disabled .page-link {
color: #6c757d;
pointer-events: none;
cursor: auto;
background-color: #fff;
border-color: #dee2e6;
}
.pagination-lg .page-link {
padding: 0.75rem 1.5rem;
font-size: 1.25rem;
line-height: 1.5;
}
.pagination-lg .page-item:first-child .page-link {
border-top-left-radius: 0.3rem;
border-bottom-left-radius: 0.3rem;
}
.pagination-lg .page-item:last-child .page-link {
border-top-right-radius: 0.3rem;
border-bottom-right-radius: 0.3rem;
}
.pagination-sm .page-link {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
line-height: 1.5;
}
.pagination-sm .page-item:first-child .page-link {
border-top-left-radius: 0.2rem;
border-bottom-left-radius: 0.2rem;
}
.pagination-sm .page-item:last-child .page-link {
border-top-right-radius: 0.2rem;
border-bottom-right-radius: 0.2rem;
}
.badge {
display: inline-block;
padding: 0.25em 0.4em;
font-size: 75%;
font-weight: 700;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: 0.25rem;
}
.badge:empty {
display: none;
}
.btn .badge {
position: relative;
top: -1px;
}
.badge-pill {
padding-right: 0.6em;
padding-left: 0.6em;
border-radius: 10rem;
}
.badge-primary {
color: #fff;
background-color: #007bff;
}
.badge-primary[href]:hover, .badge-primary[href]:focus {
color: #fff;
text-decoration: none;
background-color: #0062cc;
}
.badge-secondary {
color: #fff;
background-color: #6c757d;
}
.badge-secondary[href]:hover, .badge-secondary[href]:focus {
color: #fff;
text-decoration: none;
background-color: #545b62;
}
.badge-success {
color: #fff;
background-color: #28a745;
}
.badge-success[href]:hover, .badge-success[href]:focus {
color: #fff;
text-decoration: none;
background-color: #1e7e34;
}
.badge-info {
color: #fff;
background-color: #17a2b8;
}
.badge-info[href]:hover, .badge-info[href]:focus {
color: #fff;
text-decoration: none;
background-color: #117a8b;
}
.badge-warning {
color: #212529;
background-color: #ffc107;
}
.badge-warning[href]:hover, .badge-warning[href]:focus {
color: #212529;
text-decoration: none;
background-color: #d39e00;
}
.badge-danger {
color: #fff;
background-color: #dc3545;
}
.badge-danger[href]:hover, .badge-danger[href]:focus {
color: #fff;
text-decoration: none;
background-color: #bd2130;
}
.badge-light {
color: #212529;
background-color: #f8f9fa;
}
.badge-light[href]:hover, .badge-light[href]:focus {
color: #212529;
text-decoration: none;
background-color: #dae0e5;
}
.badge-dark {
color: #fff;
background-color: #343a40;
}
.badge-dark[href]:hover, .badge-dark[href]:focus {
color: #fff;
text-decoration: none;
background-color: #1d2124;
}
.jumbotron {
padding: 2rem 1rem;
margin-bottom: 2rem;
background-color: #e9ecef;
border-radius: 0.3rem;
}
@media (min-width: 576px) {
.jumbotron {
padding: 4rem 2rem;
}
}
.jumbotron-fluid {
padding-right: 0;
padding-left: 0;
border-radius: 0;
}
.alert {
position: relative;
padding: 0.75rem 1.25rem;
margin-bottom: 1rem;
border: 1px solid transparent;
border-radius: 0.25rem;
}
.alert-heading {
color: inherit;
}
.alert-link {
font-weight: 700;
}
.alert-dismissible {
padding-right: 4rem;
}
.alert-dismissible .close {
position: absolute;
top: 0;
right: 0;
padding: 0.75rem 1.25rem;
color: inherit;
}
.alert-primary {
color: #004085;
background-color: #cce5ff;
border-color: #b8daff;
}
.alert-primary hr {
border-top-color: #9fcdff;
}
.alert-primary .alert-link {
color: #002752;
}
.alert-secondary {
color: #383d41;
background-color: #e2e3e5;
border-color: #d6d8db;
}
.alert-secondary hr {
border-top-color: #c8cbcf;
}
.alert-secondary .alert-link {
color: #202326;
}
.alert-success {
color: #155724;
background-color: #d4edda;
border-color: #c3e6cb;
}
.alert-success hr {
border-top-color: #b1dfbb;
}
.alert-success .alert-link {
color: #0b2e13;
}
.alert-info {
color: #0c5460;
background-color: #d1ecf1;
border-color: #bee5eb;
}
.alert-info hr {
border-top-color: #abdde5;
}
.alert-info .alert-link {
color: #062c33;
}
.alert-warning {
color: #856404;
background-color: #fff3cd;
border-color: #ffeeba;
}
.alert-warning hr {
border-top-color: #ffe8a1;
}
.alert-warning .alert-link {
color: #533f03;
}
.alert-danger {
color: #721c24;
background-color: #f8d7da;
border-color: #f5c6cb;
}
.alert-danger hr {
border-top-color: #f1b0b7;
}
.alert-danger .alert-link {
color: #491217;
}
.alert-light {
color: #818182;
background-color: #fefefe;
border-color: #fdfdfe;
}
.alert-light hr {
border-top-color: #ececf6;
}
.alert-light .alert-link {
color: #686868;
}
.alert-dark {
color: #1b1e21;
background-color: #d6d8d9;
border-color: #c6c8ca;
}
.alert-dark hr {
border-top-color: #b9bbbe;
}
.alert-dark .alert-link {
color: #040505;
}
@-webkit-keyframes progress-bar-stripes {
from {
background-position: 1rem 0;
}
to {
background-position: 0 0;
}
}
@keyframes progress-bar-stripes {
from {
background-position: 1rem 0;
}
to {
background-position: 0 0;
}
}
.progress {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 1rem;
overflow: hidden;
font-size: 0.75rem;
background-color: #e9ecef;
border-radius: 0.25rem;
}
.progress-bar {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
color: #fff;
text-align: center;
background-color: #007bff;
transition: width 0.6s ease;
}
.progress-bar-striped {
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-size: 1rem 1rem;
}
.progress-bar-animated {
-webkit-animation: progress-bar-stripes 1s linear infinite;
animation: progress-bar-stripes 1s linear infinite;
}
.media {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
}
.media-body {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
}
.list-group {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
padding-left: 0;
margin-bottom: 0;
}
.list-group-item-action {
width: 100%;
color: #495057;
text-align: inherit;
}
.list-group-item-action:hover, .list-group-item-action:focus {
color: #495057;
text-decoration: none;
background-color: #f8f9fa;
}
.list-group-item-action:active {
color: #212529;
background-color: #e9ecef;
}
.list-group-item {
position: relative;
display: block;
padding: 0.75rem 1.25rem;
margin-bottom: -1px;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, 0.125);
}
.list-group-item:first-child {
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
}
.list-group-item:last-child {
margin-bottom: 0;
border-bottom-right-radius: 0.25rem;
border-bottom-left-radius: 0.25rem;
}
.list-group-item:hover, .list-group-item:focus {
z-index: 1;
text-decoration: none;
}
.list-group-item.disabled, .list-group-item:disabled {
color: #6c757d;
background-color: #fff;
}
.list-group-item.active {
z-index: 2;
color: #fff;
background-color: #007bff;
border-color: #007bff;
}
.list-group-flush .list-group-item {
border-right: 0;
border-left: 0;
border-radius: 0;
}
.list-group-flush:first-child .list-group-item:first-child {
border-top: 0;
}
.list-group-flush:last-child .list-group-item:last-child {
border-bottom: 0;
}
.list-group-item-primary {
color: #004085;
background-color: #b8daff;
}
.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus {
color: #004085;
background-color: #9fcdff;
}
.list-group-item-primary.list-group-item-action.active {
color: #fff;
background-color: #004085;
border-color: #004085;
}
.list-group-item-secondary {
color: #383d41;
background-color: #d6d8db;
}
.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus {
color: #383d41;
background-color: #c8cbcf;
}
.list-group-item-secondary.list-group-item-action.active {
color: #fff;
background-color: #383d41;
border-color: #383d41;
}
.list-group-item-success {
color: #155724;
background-color: #c3e6cb;
}
.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus {
color: #155724;
background-color: #b1dfbb;
}
.list-group-item-success.list-group-item-action.active {
color: #fff;
background-color: #155724;
border-color: #155724;
}
.list-group-item-info {
color: #0c5460;
background-color: #bee5eb;
}
.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {
color: #0c5460;
background-color: #abdde5;
}
.list-group-item-info.list-group-item-action.active {
color: #fff;
background-color: #0c5460;
border-color: #0c5460;
}
.list-group-item-warning {
color: #856404;
background-color: #ffeeba;
}
.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus {
color: #856404;
background-color: #ffe8a1;
}
.list-group-item-warning.list-group-item-action.active {
color: #fff;
background-color: #856404;
border-color: #856404;
}
.list-group-item-danger {
color: #721c24;
background-color: #f5c6cb;
}
.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus {
color: #721c24;
background-color: #f1b0b7;
}
.list-group-item-danger.list-group-item-action.active {
color: #fff;
background-color: #721c24;
border-color: #721c24;
}
.list-group-item-light {
color: #818182;
background-color: #fdfdfe;
}
.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus {
color: #818182;
background-color: #ececf6;
}
.list-group-item-light.list-group-item-action.active {
color: #fff;
background-color: #818182;
border-color: #818182;
}
.list-group-item-dark {
color: #1b1e21;
background-color: #c6c8ca;
}
.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus {
color: #1b1e21;
background-color: #b9bbbe;
}
.list-group-item-dark.list-group-item-action.active {
color: #fff;
background-color: #1b1e21;
border-color: #1b1e21;
}
.close {
float: right;
font-size: 1.5rem;
font-weight: 700;
line-height: 1;
color: #000;
text-shadow: 0 1px 0 #fff;
opacity: .5;
}
.close:hover, .close:focus {
color: #000;
text-decoration: none;
opacity: .75;
}
.close:not(:disabled):not(.disabled) {
cursor: pointer;
}
button.close {
padding: 0;
background-color: transparent;
border: 0;
-webkit-appearance: none;
}
.modal-open {
overflow: hidden;
}
.modal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1050;
display: none;
overflow: hidden;
outline: 0;
}
.modal-open .modal {
overflow-x: hidden;
overflow-y: auto;
}
.modal-dialog {
position: relative;
width: auto;
margin: 0.5rem;
pointer-events: none;
}
.modal.fade .modal-dialog {
transition: -webkit-transform 0.3s ease-out;
transition: transform 0.3s ease-out;
transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out;
-webkit-transform: translate(0, -25%);
transform: translate(0, -25%);
}
.modal.show .modal-dialog {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
.modal-dialog-centered {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
min-height: calc(100% - (0.5rem * 2));
}
.modal-content {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
width: 100%;
pointer-events: auto;
background-color: #fff;
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 0.3rem;
outline: 0;
}
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1040;
background-color: #000;
}
.modal-backdrop.fade {
opacity: 0;
}
.modal-backdrop.show {
opacity: 0.5;
}
.modal-header {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
padding: 1rem;
border-bottom: 1px solid #e9ecef;
border-top-left-radius: 0.3rem;
border-top-right-radius: 0.3rem;
}
.modal-header .close {
padding: 1rem;
margin: -1rem -1rem -1rem auto;
}
.modal-title {
margin-bottom: 0;
line-height: 1.5;
}
.modal-body {
position: relative;
-webkit-box-flex: 1;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
padding: 1rem;
}
.modal-footer {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: end;
-ms-flex-pack: end;
justify-content: flex-end;
padding: 1rem;
border-top: 1px solid #e9ecef;
}
.modal-footer > :not(:first-child) {
margin-left: .25rem;
}
.modal-footer > :not(:last-child) {
margin-right: .25rem;
}
.modal-scrollbar-measure {
position: absolute;
top: -9999px;
width: 50px;
height: 50px;
overflow: scroll;
}
@media (min-width: 576px) {
.modal-dialog {
max-width: 500px;
margin: 1.75rem auto;
}
.modal-dialog-centered {
min-height: calc(100% - (1.75rem * 2));
}
.modal-sm {
max-width: 300px;
}
}
@media (min-width: 992px) {
.modal-lg {
max-width: 800px;
}
}
.tooltip {
position: absolute;
z-index: 1070;
display: block;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-style: normal;
font-weight: 400;
line-height: 1.5;
text-align: left;
text-align: start;
text-decoration: none;
text-shadow: none;
text-transform: none;
letter-spacing: normal;
word-break: normal;
word-spacing: normal;
white-space: normal;
line-break: auto;
font-size: 0.875rem;
word-wrap: break-word;
opacity: 0;
}
.tooltip.show {
opacity: 0.9;
}
.tooltip .arrow {
position: absolute;
display: block;
width: 0.8rem;
height: 0.4rem;
}
.tooltip .arrow::before {
position: absolute;
content: "";
border-color: transparent;
border-style: solid;
}
.bs-tooltip-top, .bs-tooltip-auto[x-placement^="top"] {
padding: 0.4rem 0;
}
.bs-tooltip-top .arrow, .bs-tooltip-auto[x-placement^="top"] .arrow {
bottom: 0;
}
.bs-tooltip-top .arrow::before, .bs-tooltip-auto[x-placement^="top"] .arrow::before {
top: 0;
border-width: 0.4rem 0.4rem 0;
border-top-color: #000;
}
.bs-tooltip-right, .bs-tooltip-auto[x-placement^="right"] {
padding: 0 0.4rem;
}
.bs-tooltip-right .arrow, .bs-tooltip-auto[x-placement^="right"] .arrow {
left: 0;
width: 0.4rem;
height: 0.8rem;
}
.bs-tooltip-right .arrow::before, .bs-tooltip-auto[x-placement^="right"] .arrow::before {
right: 0;
border-width: 0.4rem 0.4rem 0.4rem 0;
border-right-color: #000;
}
.bs-tooltip-bottom, .bs-tooltip-auto[x-placement^="bottom"] {
padding: 0.4rem 0;
}
.bs-tooltip-bottom .arrow, .bs-tooltip-auto[x-placement^="bottom"] .arrow {
top: 0;
}
.bs-tooltip-bottom .arrow::before, .bs-tooltip-auto[x-placement^="bottom"] .arrow::before {
bottom: 0;
border-width: 0 0.4rem 0.4rem;
border-bottom-color: #000;
}
.bs-tooltip-left, .bs-tooltip-auto[x-placement^="left"] {
padding: 0 0.4rem;
}
.bs-tooltip-left .arrow, .bs-tooltip-auto[x-placement^="left"] .arrow {
right: 0;
width: 0.4rem;
height: 0.8rem;
}
.bs-tooltip-left .arrow::before, .bs-tooltip-auto[x-placement^="left"] .arrow::before {
left: 0;
border-width: 0.4rem 0 0.4rem 0.4rem;
border-left-color: #000;
}
.tooltip-inner {
max-width: 200px;
padding: 0.25rem 0.5rem;
color: #fff;
text-align: center;
background-color: #000;
border-radius: 0.25rem;
}
.popover {
position: absolute;
top: 0;
left: 0;
z-index: 1060;
display: block;
max-width: 276px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-style: normal;
font-weight: 400;
line-height: 1.5;
text-align: left;
text-align: start;
text-decoration: none;
text-shadow: none;
text-transform: none;
letter-spacing: normal;
word-break: normal;
word-spacing: normal;
white-space: normal;
line-break: auto;
font-size: 0.875rem;
word-wrap: break-word;
background-color: #fff;
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 0.3rem;
}
.popover .arrow {
position: absolute;
display: block;
width: 1rem;
height: 0.5rem;
margin: 0 0.3rem;
}
.popover .arrow::before, .popover .arrow::after {
position: absolute;
display: block;
content: "";
border-color: transparent;
border-style: solid;
}
.bs-popover-top, .bs-popover-auto[x-placement^="top"] {
margin-bottom: 0.5rem;
}
.bs-popover-top .arrow, .bs-popover-auto[x-placement^="top"] .arrow {
bottom: calc((0.5rem + 1px) * -1);
}
.bs-popover-top .arrow::before, .bs-popover-auto[x-placement^="top"] .arrow::before,
.bs-popover-top .arrow::after, .bs-popover-auto[x-placement^="top"] .arrow::after {
border-width: 0.5rem 0.5rem 0;
}
.bs-popover-top .arrow::before, .bs-popover-auto[x-placement^="top"] .arrow::before {
bottom: 0;
border-top-color: rgba(0, 0, 0, 0.25);
}
.bs-popover-top .arrow::after, .bs-popover-auto[x-placement^="top"] .arrow::after {
bottom: 1px;
border-top-color: #fff;
}
.bs-popover-right, .bs-popover-auto[x-placement^="right"] {
margin-left: 0.5rem;
}
.bs-popover-right .arrow, .bs-popover-auto[x-placement^="right"] .arrow {
left: calc((0.5rem + 1px) * -1);
width: 0.5rem;
height: 1rem;
margin: 0.3rem 0;
}
.bs-popover-right .arrow::before, .bs-popover-auto[x-placement^="right"] .arrow::before,
.bs-popover-right .arrow::after, .bs-popover-auto[x-placement^="right"] .arrow::after {
border-width: 0.5rem 0.5rem 0.5rem 0;
}
.bs-popover-right .arrow::before, .bs-popover-auto[x-placement^="right"] .arrow::before {
left: 0;
border-right-color: rgba(0, 0, 0, 0.25);
}
.bs-popover-right .arrow::after, .bs-popover-auto[x-placement^="right"] .arrow::after {
left: 1px;
border-right-color: #fff;
}
.bs-popover-bottom, .bs-popover-auto[x-placement^="bottom"] {
margin-top: 0.5rem;
}
.bs-popover-bottom .arrow, .bs-popover-auto[x-placement^="bottom"] .arrow {
top: calc((0.5rem + 1px) * -1);
}
.bs-popover-bottom .arrow::before, .bs-popover-auto[x-placement^="bottom"] .arrow::before,
.bs-popover-bottom .arrow::after, .bs-popover-auto[x-placement^="bottom"] .arrow::after {
border-width: 0 0.5rem 0.5rem 0.5rem;
}
.bs-popover-bottom .arrow::before, .bs-popover-auto[x-placement^="bottom"] .arrow::before {
top: 0;
border-bottom-color: rgba(0, 0, 0, 0.25);
}
.bs-popover-bottom .arrow::after, .bs-popover-auto[x-placement^="bottom"] .arrow::after {
top: 1px;
border-bottom-color: #fff;
}
.bs-popover-bottom .popover-header::before, .bs-popover-auto[x-placement^="bottom"] .popover-header::before {
position: absolute;
top: 0;
left: 50%;
display: block;
width: 1rem;
margin-left: -0.5rem;
content: "";
border-bottom: 1px solid #f7f7f7;
}
.bs-popover-left, .bs-popover-auto[x-placement^="left"] {
margin-right: 0.5rem;
}
.bs-popover-left .arrow, .bs-popover-auto[x-placement^="left"] .arrow {
right: calc((0.5rem + 1px) * -1);
width: 0.5rem;
height: 1rem;
margin: 0.3rem 0;
}
.bs-popover-left .arrow::before, .bs-popover-auto[x-placement^="left"] .arrow::before,
.bs-popover-left .arrow::after, .bs-popover-auto[x-placement^="left"] .arrow::after {
border-width: 0.5rem 0 0.5rem 0.5rem;
}
.bs-popover-left .arrow::before, .bs-popover-auto[x-placement^="left"] .arrow::before {
right: 0;
border-left-color: rgba(0, 0, 0, 0.25);
}
.bs-popover-left .arrow::after, .bs-popover-auto[x-placement^="left"] .arrow::after {
right: 1px;
border-left-color: #fff;
}
.popover-header {
padding: 0.5rem 0.75rem;
margin-bottom: 0;
font-size: 1rem;
color: inherit;
background-color: #f7f7f7;
border-bottom: 1px solid #ebebeb;
border-top-left-radius: calc(0.3rem - 1px);
border-top-right-radius: calc(0.3rem - 1px);
}
.popover-header:empty {
display: none;
}
.popover-body {
padding: 0.5rem 0.75rem;
color: #212529;
}
.carousel {
position: relative;
}
.carousel-inner {
position: relative;
width: 100%;
overflow: hidden;
}
.carousel-item {
position: relative;
display: none;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
width: 100%;
transition: -webkit-transform 0.6s ease;
transition: transform 0.6s ease;
transition: transform 0.6s ease, -webkit-transform 0.6s ease;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-perspective: 1000px;
perspective: 1000px;
}
.carousel-item.active,
.carousel-item-next,
.carousel-item-prev {
display: block;
}
.carousel-item-next,
.carousel-item-prev {
position: absolute;
top: 0;
}
.carousel-item-next.carousel-item-left,
.carousel-item-prev.carousel-item-right {
-webkit-transform: translateX(0);
transform: translateX(0);
}
@supports ((-webkit-transform-style: preserve-3d) or (transform-style: preserve-3d)) {
.carousel-item-next.carousel-item-left,
.carousel-item-prev.carousel-item-right {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
.carousel-item-next,
.active.carousel-item-right {
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
@supports ((-webkit-transform-style: preserve-3d) or (transform-style: preserve-3d)) {
.carousel-item-next,
.active.carousel-item-right {
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
}
.carousel-item-prev,
.active.carousel-item-left {
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
@supports ((-webkit-transform-style: preserve-3d) or (transform-style: preserve-3d)) {
.carousel-item-prev,
.active.carousel-item-left {
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
}
.carousel-control-prev,
.carousel-control-next {
position: absolute;
top: 0;
bottom: 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
width: 15%;
color: #fff;
text-align: center;
opacity: 0.5;
}
.carousel-control-prev:hover, .carousel-control-prev:focus,
.carousel-control-next:hover,
.carousel-control-next:focus {
color: #fff;
text-decoration: none;
outline: 0;
opacity: .9;
}
.carousel-control-prev {
left: 0;
}
.carousel-control-next {
right: 0;
}
.carousel-control-prev-icon,
.carousel-control-next-icon {
display: inline-block;
width: 20px;
height: 20px;
background: transparent no-repeat center center;
background-size: 100% 100%;
}
.carousel-control-prev-icon {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E");
}
.carousel-control-next-icon {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E");
}
.carousel-indicators {
position: absolute;
right: 0;
bottom: 10px;
left: 0;
z-index: 15;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
padding-left: 0;
margin-right: 15%;
margin-left: 15%;
list-style: none;
}
.carousel-indicators li {
position: relative;
-webkit-box-flex: 0;
-ms-flex: 0 1 auto;
flex: 0 1 auto;
width: 30px;
height: 3px;
margin-right: 3px;
margin-left: 3px;
text-indent: -999px;
background-color: rgba(255, 255, 255, 0.5);
}
.carousel-indicators li::before {
position: absolute;
top: -10px;
left: 0;
display: inline-block;
width: 100%;
height: 10px;
content: "";
}
.carousel-indicators li::after {
position: absolute;
bottom: -10px;
left: 0;
display: inline-block;
width: 100%;
height: 10px;
content: "";
}
.carousel-indicators .active {
background-color: #fff;
}
.carousel-caption {
position: absolute;
right: 15%;
bottom: 20px;
left: 15%;
z-index: 10;
padding-top: 20px;
padding-bottom: 20px;
color: #fff;
text-align: center;
}
.align-baseline {
vertical-align: baseline !important;
}
.align-top {
vertical-align: top !important;
}
.align-middle {
vertical-align: middle !important;
}
.align-bottom {
vertical-align: bottom !important;
}
.align-text-bottom {
vertical-align: text-bottom !important;
}
.align-text-top {
vertical-align: text-top !important;
}
.bg-primary {
background-color: #007bff !important;
}
a.bg-primary:hover, a.bg-primary:focus,
button.bg-primary:hover,
button.bg-primary:focus {
background-color: #0062cc !important;
}
.bg-secondary {
background-color: #6c757d !important;
}
a.bg-secondary:hover, a.bg-secondary:focus,
button.bg-secondary:hover,
button.bg-secondary:focus {
background-color: #545b62 !important;
}
.bg-success {
background-color: #28a745 !important;
}
a.bg-success:hover, a.bg-success:focus,
button.bg-success:hover,
button.bg-success:focus {
background-color: #1e7e34 !important;
}
.bg-info {
background-color: #17a2b8 !important;
}
a.bg-info:hover, a.bg-info:focus,
button.bg-info:hover,
button.bg-info:focus {
background-color: #117a8b !important;
}
.bg-warning {
background-color: #ffc107 !important;
}
a.bg-warning:hover, a.bg-warning:focus,
button.bg-warning:hover,
button.bg-warning:focus {
background-color: #d39e00 !important;
}
.bg-danger {
background-color: #dc3545 !important;
}
a.bg-danger:hover, a.bg-danger:focus,
button.bg-danger:hover,
button.bg-danger:focus {
background-color: #bd2130 !important;
}
.bg-light {
background-color: #f8f9fa !important;
}
a.bg-light:hover, a.bg-light:focus,
button.bg-light:hover,
button.bg-light:focus {
background-color: #dae0e5 !important;
}
.bg-dark {
background-color: #343a40 !important;
}
a.bg-dark:hover, a.bg-dark:focus,
button.bg-dark:hover,
button.bg-dark:focus {
background-color: #1d2124 !important;
}
.bg-white {
background-color: #fff !important;
}
.bg-transparent {
background-color: transparent !important;
}
.border {
border: 1px solid #dee2e6 !important;
}
.border-top {
border-top: 1px solid #dee2e6 !important;
}
.border-right {
border-right: 1px solid #dee2e6 !important;
}
.border-bottom {
border-bottom: 1px solid #dee2e6 !important;
}
.border-left {
border-left: 1px solid #dee2e6 !important;
}
.border-0 {
border: 0 !important;
}
.border-top-0 {
border-top: 0 !important;
}
.border-right-0 {
border-right: 0 !important;
}
.border-bottom-0 {
border-bottom: 0 !important;
}
.border-left-0 {
border-left: 0 !important;
}
.border-primary {
border-color: #007bff !important;
}
.border-secondary {
border-color: #6c757d !important;
}
.border-success {
border-color: #28a745 !important;
}
.border-info {
border-color: #17a2b8 !important;
}
.border-warning {
border-color: #ffc107 !important;
}
.border-danger {
border-color: #dc3545 !important;
}
.border-light {
border-color: #f8f9fa !important;
}
.border-dark {
border-color: #343a40 !important;
}
.border-white {
border-color: #fff !important;
}
.rounded {
border-radius: 0.25rem !important;
}
.rounded-top {
border-top-left-radius: 0.25rem !important;
border-top-right-radius: 0.25rem !important;
}
.rounded-right {
border-top-right-radius: 0.25rem !important;
border-bottom-right-radius: 0.25rem !important;
}
.rounded-bottom {
border-bottom-right-radius: 0.25rem !important;
border-bottom-left-radius: 0.25rem !important;
}
.rounded-left {
border-top-left-radius: 0.25rem !important;
border-bottom-left-radius: 0.25rem !important;
}
.rounded-circle {
border-radius: 50% !important;
}
.rounded-0 {
border-radius: 0 !important;
}
.clearfix::after {
display: block;
clear: both;
content: "";
}
.d-none {
display: none !important;
}
.d-inline {
display: inline !important;
}
.d-inline-block {
display: inline-block !important;
}
.d-block {
display: block !important;
}
.d-table {
display: table !important;
}
.d-table-row {
display: table-row !important;
}
.d-table-cell {
display: table-cell !important;
}
.d-flex {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
}
.d-inline-flex {
display: -webkit-inline-box !important;
display: -ms-inline-flexbox !important;
display: inline-flex !important;
}
@media (min-width: 576px) {
.d-sm-none {
display: none !important;
}
.d-sm-inline {
display: inline !important;
}
.d-sm-inline-block {
display: inline-block !important;
}
.d-sm-block {
display: block !important;
}
.d-sm-table {
display: table !important;
}
.d-sm-table-row {
display: table-row !important;
}
.d-sm-table-cell {
display: table-cell !important;
}
.d-sm-flex {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
}
.d-sm-inline-flex {
display: -webkit-inline-box !important;
display: -ms-inline-flexbox !important;
display: inline-flex !important;
}
}
@media (min-width: 768px) {
.d-md-none {
display: none !important;
}
.d-md-inline {
display: inline !important;
}
.d-md-inline-block {
display: inline-block !important;
}
.d-md-block {
display: block !important;
}
.d-md-table {
display: table !important;
}
.d-md-table-row {
display: table-row !important;
}
.d-md-table-cell {
display: table-cell !important;
}
.d-md-flex {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
}
.d-md-inline-flex {
display: -webkit-inline-box !important;
display: -ms-inline-flexbox !important;
display: inline-flex !important;
}
}
@media (min-width: 992px) {
.d-lg-none {
display: none !important;
}
.d-lg-inline {
display: inline !important;
}
.d-lg-inline-block {
display: inline-block !important;
}
.d-lg-block {
display: block !important;
}
.d-lg-table {
display: table !important;
}
.d-lg-table-row {
display: table-row !important;
}
.d-lg-table-cell {
display: table-cell !important;
}
.d-lg-flex {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
}
.d-lg-inline-flex {
display: -webkit-inline-box !important;
display: -ms-inline-flexbox !important;
display: inline-flex !important;
}
}
@media (min-width: 1200px) {
.d-xl-none {
display: none !important;
}
.d-xl-inline {
display: inline !important;
}
.d-xl-inline-block {
display: inline-block !important;
}
.d-xl-block {
display: block !important;
}
.d-xl-table {
display: table !important;
}
.d-xl-table-row {
display: table-row !important;
}
.d-xl-table-cell {
display: table-cell !important;
}
.d-xl-flex {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
}
.d-xl-inline-flex {
display: -webkit-inline-box !important;
display: -ms-inline-flexbox !important;
display: inline-flex !important;
}
}
@media print {
.d-print-none {
display: none !important;
}
.d-print-inline {
display: inline !important;
}
.d-print-inline-block {
display: inline-block !important;
}
.d-print-block {
display: block !important;
}
.d-print-table {
display: table !important;
}
.d-print-table-row {
display: table-row !important;
}
.d-print-table-cell {
display: table-cell !important;
}
.d-print-flex {
display: -webkit-box !important;
display: -ms-flexbox !important;
display: flex !important;
}
.d-print-inline-flex {
display: -webkit-inline-box !important;
display: -ms-inline-flexbox !important;
display: inline-flex !important;
}
}
.embed-responsive {
position: relative;
display: block;
width: 100%;
padding: 0;
overflow: hidden;
}
.embed-responsive::before {
display: block;
content: "";
}
.embed-responsive .embed-responsive-item,
.embed-responsive iframe,
.embed-responsive embed,
.embed-responsive object,
.embed-responsive video {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
.embed-responsive-21by9::before {
padding-top: 42.857143%;
}
.embed-responsive-16by9::before {
padding-top: 56.25%;
}
.embed-responsive-4by3::before {
padding-top: 75%;
}
.embed-responsive-1by1::before {
padding-top: 100%;
}
.flex-row {
-webkit-box-orient: horizontal !important;
-webkit-box-direction: normal !important;
-ms-flex-direction: row !important;
flex-direction: row !important;
}
.flex-column {
-webkit-box-orient: vertical !important;
-webkit-box-direction: normal !important;
-ms-flex-direction: column !important;
flex-direction: column !important;
}
.flex-row-reverse {
-webkit-box-orient: horizontal !important;
-webkit-box-direction: reverse !important;
-ms-flex-direction: row-reverse !important;
flex-direction: row-reverse !important;
}
.flex-column-reverse {
-webkit-box-orient: vertical !important;
-webkit-box-direction: reverse !important;
-ms-flex-direction: column-reverse !important;
flex-direction: column-reverse !important;
}
.flex-wrap {
-ms-flex-wrap: wrap !important;
flex-wrap: wrap !important;
}
.flex-nowrap {
-ms-flex-wrap: nowrap !important;
flex-wrap: nowrap !important;
}
.flex-wrap-reverse {
-ms-flex-wrap: wrap-reverse !important;
flex-wrap: wrap-reverse !important;
}
.justify-content-start {
-webkit-box-pack: start !important;
-ms-flex-pack: start !important;
justify-content: flex-start !important;
}
.justify-content-end {
-webkit-box-pack: end !important;
-ms-flex-pack: end !important;
justify-content: flex-end !important;
}
.justify-content-center {
-webkit-box-pack: center !important;
-ms-flex-pack: center !important;
justify-content: center !important;
}
.justify-content-between {
-webkit-box-pack: justify !important;
-ms-flex-pack: justify !important;
justify-content: space-between !important;
}
.justify-content-around {
-ms-flex-pack: distribute !important;
justify-content: space-around !important;
}
.align-items-start {
-webkit-box-align: start !important;
-ms-flex-align: start !important;
align-items: flex-start !important;
}
.align-items-end {
-webkit-box-align: end !important;
-ms-flex-align: end !important;
align-items: flex-end !important;
}
.align-items-center {
-webkit-box-align: center !important;
-ms-flex-align: center !important;
align-items: center !important;
}
.align-items-baseline {
-webkit-box-align: baseline !important;
-ms-flex-align: baseline !important;
align-items: baseline !important;
}
.align-items-stretch {
-webkit-box-align: stretch !important;
-ms-flex-align: stretch !important;
align-items: stretch !important;
}
.align-content-start {
-ms-flex-line-pack: start !important;
align-content: flex-start !important;
}
.align-content-end {
-ms-flex-line-pack: end !important;
align-content: flex-end !important;
}
.align-content-center {
-ms-flex-line-pack: center !important;
align-content: center !important;
}
.align-content-between {
-ms-flex-line-pack: justify !important;
align-content: space-between !important;
}
.align-content-around {
-ms-flex-line-pack: distribute !important;
align-content: space-around !important;
}
.align-content-stretch {
-ms-flex-line-pack: stretch !important;
align-content: stretch !important;
}
.align-self-auto {
-ms-flex-item-align: auto !important;
align-self: auto !important;
}
.align-self-start {
-ms-flex-item-align: start !important;
align-self: flex-start !important;
}
.align-self-end {
-ms-flex-item-align: end !important;
align-self: flex-end !important;
}
.align-self-center {
-ms-flex-item-align: center !important;
align-self: center !important;
}
.align-self-baseline {
-ms-flex-item-align: baseline !important;
align-self: baseline !important;
}
.align-self-stretch {
-ms-flex-item-align: stretch !important;
align-self: stretch !important;
}
@media (min-width: 576px) {
.flex-sm-row {
-webkit-box-orient: horizontal !important;
-webkit-box-direction: normal !important;
-ms-flex-direction: row !important;
flex-direction: row !important;
}
.flex-sm-column {
-webkit-box-orient: vertical !important;
-webkit-box-direction: normal !important;
-ms-flex-direction: column !important;
flex-direction: column !important;
}
.flex-sm-row-reverse {
-webkit-box-orient: horizontal !important;
-webkit-box-direction: reverse !important;
-ms-flex-direction: row-reverse !important;
flex-direction: row-reverse !important;
}
.flex-sm-column-reverse {
-webkit-box-orient: vertical !important;
-webkit-box-direction: reverse !important;
-ms-flex-direction: column-reverse !important;
flex-direction: column-reverse !important;
}
.flex-sm-wrap {
-ms-flex-wrap: wrap !important;
flex-wrap: wrap !important;
}
.flex-sm-nowrap {
-ms-flex-wrap: nowrap !important;
flex-wrap: nowrap !important;
}
.flex-sm-wrap-reverse {
-ms-flex-wrap: wrap-reverse !important;
flex-wrap: wrap-reverse !important;
}
.justify-content-sm-start {
-webkit-box-pack: start !important;
-ms-flex-pack: start !important;
justify-content: flex-start !important;
}
.justify-content-sm-end {
-webkit-box-pack: end !important;
-ms-flex-pack: end !important;
justify-content: flex-end !important;
}
.justify-content-sm-center {
-webkit-box-pack: center !important;
-ms-flex-pack: center !important;
justify-content: center !important;
}
.justify-content-sm-between {
-webkit-box-pack: justify !important;
-ms-flex-pack: justify !important;
justify-content: space-between !important;
}
.justify-content-sm-around {
-ms-flex-pack: distribute !important;
justify-content: space-around !important;
}
.align-items-sm-start {
-webkit-box-align: start !important;
-ms-flex-align: start !important;
align-items: flex-start !important;
}
.align-items-sm-end {
-webkit-box-align: end !important;
-ms-flex-align: end !important;
align-items: flex-end !important;
}
.align-items-sm-center {
-webkit-box-align: center !important;
-ms-flex-align: center !important;
align-items: center !important;
}
.align-items-sm-baseline {
-webkit-box-align: baseline !important;
-ms-flex-align: baseline !important;
align-items: baseline !important;
}
.align-items-sm-stretch {
-webkit-box-align: stretch !important;
-ms-flex-align: stretch !important;
align-items: stretch !important;
}
.align-content-sm-start {
-ms-flex-line-pack: start !important;
align-content: flex-start !important;
}
.align-content-sm-end {
-ms-flex-line-pack: end !important;
align-content: flex-end !important;
}
.align-content-sm-center {
-ms-flex-line-pack: center !important;
align-content: center !important;
}
.align-content-sm-between {
-ms-flex-line-pack: justify !important;
align-content: space-between !important;
}
.align-content-sm-around {
-ms-flex-line-pack: distribute !important;
align-content: space-around !important;
}
.align-content-sm-stretch {
-ms-flex-line-pack: stretch !important;
align-content: stretch !important;
}
.align-self-sm-auto {
-ms-flex-item-align: auto !important;
align-self: auto !important;
}
.align-self-sm-start {
-ms-flex-item-align: start !important;
align-self: flex-start !important;
}
.align-self-sm-end {
-ms-flex-item-align: end !important;
align-self: flex-end !important;
}
.align-self-sm-center {
-ms-flex-item-align: center !important;
align-self: center !important;
}
.align-self-sm-baseline {
-ms-flex-item-align: baseline !important;
align-self: baseline !important;
}
.align-self-sm-stretch {
-ms-flex-item-align: stretch !important;
align-self: stretch !important;
}
}
@media (min-width: 768px) {
.flex-md-row {
-webkit-box-orient: horizontal !important;
-webkit-box-direction: normal !important;
-ms-flex-direction: row !important;
flex-direction: row !important;
}
.flex-md-column {
-webkit-box-orient: vertical !important;
-webkit-box-direction: normal !important;
-ms-flex-direction: column !important;
flex-direction: column !important;
}
.flex-md-row-reverse {
-webkit-box-orient: horizontal !important;
-webkit-box-direction: reverse !important;
-ms-flex-direction: row-reverse !important;
flex-direction: row-reverse !important;
}
.flex-md-column-reverse {
-webkit-box-orient: vertical !important;
-webkit-box-direction: reverse !important;
-ms-flex-direction: column-reverse !important;
flex-direction: column-reverse !important;
}
.flex-md-wrap {
-ms-flex-wrap: wrap !important;
flex-wrap: wrap !important;
}
.flex-md-nowrap {
-ms-flex-wrap: nowrap !important;
flex-wrap: nowrap !important;
}
.flex-md-wrap-reverse {
-ms-flex-wrap: wrap-reverse !important;
flex-wrap: wrap-reverse !important;
}
.justify-content-md-start {
-webkit-box-pack: start !important;
-ms-flex-pack: start !important;
justify-content: flex-start !important;
}
.justify-content-md-end {
-webkit-box-pack: end !important;
-ms-flex-pack: end !important;
justify-content: flex-end !important;
}
.justify-content-md-center {
-webkit-box-pack: center !important;
-ms-flex-pack: center !important;
justify-content: center !important;
}
.justify-content-md-between {
-webkit-box-pack: justify !important;
-ms-flex-pack: justify !important;
justify-content: space-between !important;
}
.justify-content-md-around {
-ms-flex-pack: distribute !important;
justify-content: space-around !important;
}
.align-items-md-start {
-webkit-box-align: start !important;
-ms-flex-align: start !important;
align-items: flex-start !important;
}
.align-items-md-end {
-webkit-box-align: end !important;
-ms-flex-align: end !important;
align-items: flex-end !important;
}
.align-items-md-center {
-webkit-box-align: center !important;
-ms-flex-align: center !important;
align-items: center !important;
}
.align-items-md-baseline {
-webkit-box-align: baseline !important;
-ms-flex-align: baseline !important;
align-items: baseline !important;
}
.align-items-md-stretch {
-webkit-box-align: stretch !important;
-ms-flex-align: stretch !important;
align-items: stretch !important;
}
.align-content-md-start {
-ms-flex-line-pack: start !important;
align-content: flex-start !important;
}
.align-content-md-end {
-ms-flex-line-pack: end !important;
align-content: flex-end !important;
}
.align-content-md-center {
-ms-flex-line-pack: center !important;
align-content: center !important;
}
.align-content-md-between {
-ms-flex-line-pack: justify !important;
align-content: space-between !important;
}
.align-content-md-around {
-ms-flex-line-pack: distribute !important;
align-content: space-around !important;
}
.align-content-md-stretch {
-ms-flex-line-pack: stretch !important;
align-content: stretch !important;
}
.align-self-md-auto {
-ms-flex-item-align: auto !important;
align-self: auto !important;
}
.align-self-md-start {
-ms-flex-item-align: start !important;
align-self: flex-start !important;
}
.align-self-md-end {
-ms-flex-item-align: end !important;
align-self: flex-end !important;
}
.align-self-md-center {
-ms-flex-item-align: center !important;
align-self: center !important;
}
.align-self-md-baseline {
-ms-flex-item-align: baseline !important;
align-self: baseline !important;
}
.align-self-md-stretch {
-ms-flex-item-align: stretch !important;
align-self: stretch !important;
}
}
@media (min-width: 992px) {
.flex-lg-row {
-webkit-box-orient: horizontal !important;
-webkit-box-direction: normal !important;
-ms-flex-direction: row !important;
flex-direction: row !important;
}
.flex-lg-column {
-webkit-box-orient: vertical !important;
-webkit-box-direction: normal !important;
-ms-flex-direction: column !important;
flex-direction: column !important;
}
.flex-lg-row-reverse {
-webkit-box-orient: horizontal !important;
-webkit-box-direction: reverse !important;
-ms-flex-direction: row-reverse !important;
flex-direction: row-reverse !important;
}
.flex-lg-column-reverse {
-webkit-box-orient: vertical !important;
-webkit-box-direction: reverse !important;
-ms-flex-direction: column-reverse !important;
flex-direction: column-reverse !important;
}
.flex-lg-wrap {
-ms-flex-wrap: wrap !important;
flex-wrap: wrap !important;
}
.flex-lg-nowrap {
-ms-flex-wrap: nowrap !important;
flex-wrap: nowrap !important;
}
.flex-lg-wrap-reverse {
-ms-flex-wrap: wrap-reverse !important;
flex-wrap: wrap-reverse !important;
}
.justify-content-lg-start {
-webkit-box-pack: start !important;
-ms-flex-pack: start !important;
justify-content: flex-start !important;
}
.justify-content-lg-end {
-webkit-box-pack: end !important;
-ms-flex-pack: end !important;
justify-content: flex-end !important;
}
.justify-content-lg-center {
-webkit-box-pack: center !important;
-ms-flex-pack: center !important;
justify-content: center !important;
}
.justify-content-lg-between {
-webkit-box-pack: justify !important;
-ms-flex-pack: justify !important;
justify-content: space-between !important;
}
.justify-content-lg-around {
-ms-flex-pack: distribute !important;
justify-content: space-around !important;
}
.align-items-lg-start {
-webkit-box-align: start !important;
-ms-flex-align: start !important;
align-items: flex-start !important;
}
.align-items-lg-end {
-webkit-box-align: end !important;
-ms-flex-align: end !important;
align-items: flex-end !important;
}
.align-items-lg-center {
-webkit-box-align: center !important;
-ms-flex-align: center !important;
align-items: center !important;
}
.align-items-lg-baseline {
-webkit-box-align: baseline !important;
-ms-flex-align: baseline !important;
align-items: baseline !important;
}
.align-items-lg-stretch {
-webkit-box-align: stretch !important;
-ms-flex-align: stretch !important;
align-items: stretch !important;
}
.align-content-lg-start {
-ms-flex-line-pack: start !important;
align-content: flex-start !important;
}
.align-content-lg-end {
-ms-flex-line-pack: end !important;
align-content: flex-end !important;
}
.align-content-lg-center {
-ms-flex-line-pack: center !important;
align-content: center !important;
}
.align-content-lg-between {
-ms-flex-line-pack: justify !important;
align-content: space-between !important;
}
.align-content-lg-around {
-ms-flex-line-pack: distribute !important;
align-content: space-around !important;
}
.align-content-lg-stretch {
-ms-flex-line-pack: stretch !important;
align-content: stretch !important;
}
.align-self-lg-auto {
-ms-flex-item-align: auto !important;
align-self: auto !important;
}
.align-self-lg-start {
-ms-flex-item-align: start !important;
align-self: flex-start !important;
}
.align-self-lg-end {
-ms-flex-item-align: end !important;
align-self: flex-end !important;
}
.align-self-lg-center {
-ms-flex-item-align: center !important;
align-self: center !important;
}
.align-self-lg-baseline {
-ms-flex-item-align: baseline !important;
align-self: baseline !important;
}
.align-self-lg-stretch {
-ms-flex-item-align: stretch !important;
align-self: stretch !important;
}
}
@media (min-width: 1200px) {
.flex-xl-row {
-webkit-box-orient: horizontal !important;
-webkit-box-direction: normal !important;
-ms-flex-direction: row !important;
flex-direction: row !important;
}
.flex-xl-column {
-webkit-box-orient: vertical !important;
-webkit-box-direction: normal !important;
-ms-flex-direction: column !important;
flex-direction: column !important;
}
.flex-xl-row-reverse {
-webkit-box-orient: horizontal !important;
-webkit-box-direction: reverse !important;
-ms-flex-direction: row-reverse !important;
flex-direction: row-reverse !important;
}
.flex-xl-column-reverse {
-webkit-box-orient: vertical !important;
-webkit-box-direction: reverse !important;
-ms-flex-direction: column-reverse !important;
flex-direction: column-reverse !important;
}
.flex-xl-wrap {
-ms-flex-wrap: wrap !important;
flex-wrap: wrap !important;
}
.flex-xl-nowrap {
-ms-flex-wrap: nowrap !important;
flex-wrap: nowrap !important;
}
.flex-xl-wrap-reverse {
-ms-flex-wrap: wrap-reverse !important;
flex-wrap: wrap-reverse !important;
}
.justify-content-xl-start {
-webkit-box-pack: start !important;
-ms-flex-pack: start !important;
justify-content: flex-start !important;
}
.justify-content-xl-end {
-webkit-box-pack: end !important;
-ms-flex-pack: end !important;
justify-content: flex-end !important;
}
.justify-content-xl-center {
-webkit-box-pack: center !important;
-ms-flex-pack: center !important;
justify-content: center !important;
}
.justify-content-xl-between {
-webkit-box-pack: justify !important;
-ms-flex-pack: justify !important;
justify-content: space-between !important;
}
.justify-content-xl-around {
-ms-flex-pack: distribute !important;
justify-content: space-around !important;
}
.align-items-xl-start {
-webkit-box-align: start !important;
-ms-flex-align: start !important;
align-items: flex-start !important;
}
.align-items-xl-end {
-webkit-box-align: end !important;
-ms-flex-align: end !important;
align-items: flex-end !important;
}
.align-items-xl-center {
-webkit-box-align: center !important;
-ms-flex-align: center !important;
align-items: center !important;
}
.align-items-xl-baseline {
-webkit-box-align: baseline !important;
-ms-flex-align: baseline !important;
align-items: baseline !important;
}
.align-items-xl-stretch {
-webkit-box-align: stretch !important;
-ms-flex-align: stretch !important;
align-items: stretch !important;
}
.align-content-xl-start {
-ms-flex-line-pack: start !important;
align-content: flex-start !important;
}
.align-content-xl-end {
-ms-flex-line-pack: end !important;
align-content: flex-end !important;
}
.align-content-xl-center {
-ms-flex-line-pack: center !important;
align-content: center !important;
}
.align-content-xl-between {
-ms-flex-line-pack: justify !important;
align-content: space-between !important;
}
.align-content-xl-around {
-ms-flex-line-pack: distribute !important;
align-content: space-around !important;
}
.align-content-xl-stretch {
-ms-flex-line-pack: stretch !important;
align-content: stretch !important;
}
.align-self-xl-auto {
-ms-flex-item-align: auto !important;
align-self: auto !important;
}
.align-self-xl-start {
-ms-flex-item-align: start !important;
align-self: flex-start !important;
}
.align-self-xl-end {
-ms-flex-item-align: end !important;
align-self: flex-end !important;
}
.align-self-xl-center {
-ms-flex-item-align: center !important;
align-self: center !important;
}
.align-self-xl-baseline {
-ms-flex-item-align: baseline !important;
align-self: baseline !important;
}
.align-self-xl-stretch {
-ms-flex-item-align: stretch !important;
align-self: stretch !important;
}
}
.float-left {
float: left !important;
}
.float-right {
float: right !important;
}
.float-none {
float: none !important;
}
@media (min-width: 576px) {
.float-sm-left {
float: left !important;
}
.float-sm-right {
float: right !important;
}
.float-sm-none {
float: none !important;
}
}
@media (min-width: 768px) {
.float-md-left {
float: left !important;
}
.float-md-right {
float: right !important;
}
.float-md-none {
float: none !important;
}
}
@media (min-width: 992px) {
.float-lg-left {
float: left !important;
}
.float-lg-right {
float: right !important;
}
.float-lg-none {
float: none !important;
}
}
@media (min-width: 1200px) {
.float-xl-left {
float: left !important;
}
.float-xl-right {
float: right !important;
}
.float-xl-none {
float: none !important;
}
}
.position-static {
position: static !important;
}
.position-relative {
position: relative !important;
}
.position-absolute {
position: absolute !important;
}
.position-fixed {
position: fixed !important;
}
.position-sticky {
position: -webkit-sticky !important;
position: sticky !important;
}
.fixed-top {
position: fixed;
top: 0;
right: 0;
left: 0;
z-index: 1030;
}
.fixed-bottom {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 1030;
}
@supports ((position: -webkit-sticky) or (position: sticky)) {
.sticky-top {
position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 1020;
}
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
-webkit-clip-path: inset(50%);
clip-path: inset(50%);
border: 0;
}
.sr-only-focusable:active, .sr-only-focusable:focus {
position: static;
width: auto;
height: auto;
overflow: visible;
clip: auto;
white-space: normal;
-webkit-clip-path: none;
clip-path: none;
}
.w-25 {
width: 25% !important;
}
.w-50 {
width: 50% !important;
}
.w-75 {
width: 75% !important;
}
.w-100 {
width: 100% !important;
}
.h-25 {
height: 25% !important;
}
.h-50 {
height: 50% !important;
}
.h-75 {
height: 75% !important;
}
.h-100 {
height: 100% !important;
}
.mw-100 {
max-width: 100% !important;
}
.mh-100 {
max-height: 100% !important;
}
.m-0 {
margin: 0 !important;
}
.mt-0,
.my-0 {
margin-top: 0 !important;
}
.mr-0,
.mx-0 {
margin-right: 0 !important;
}
.mb-0,
.my-0 {
margin-bottom: 0 !important;
}
.ml-0,
.mx-0 {
margin-left: 0 !important;
}
.m-1 {
margin: 0.25rem !important;
}
.mt-1,
.my-1 {
margin-top: 0.25rem !important;
}
.mr-1,
.mx-1 {
margin-right: 0.25rem !important;
}
.mb-1,
.my-1 {
margin-bottom: 0.25rem !important;
}
.ml-1,
.mx-1 {
margin-left: 0.25rem !important;
}
.m-2 {
margin: 0.5rem !important;
}
.mt-2,
.my-2 {
margin-top: 0.5rem !important;
}
.mr-2,
.mx-2 {
margin-right: 0.5rem !important;
}
.mb-2,
.my-2 {
margin-bottom: 0.5rem !important;
}
.ml-2,
.mx-2 {
margin-left: 0.5rem !important;
}
.m-3 {
margin: 1rem !important;
}
.mt-3,
.my-3 {
margin-top: 1rem !important;
}
.mr-3,
.mx-3 {
margin-right: 1rem !important;
}
.mb-3,
.my-3 {
margin-bottom: 1rem !important;
}
.ml-3,
.mx-3 {
margin-left: 1rem !important;
}
.m-4 {
margin: 1.5rem !important;
}
.mt-4,
.my-4 {
margin-top: 1.5rem !important;
}
.mr-4,
.mx-4 {
margin-right: 1.5rem !important;
}
.mb-4,
.my-4 {
margin-bottom: 1.5rem !important;
}
.ml-4,
.mx-4 {
margin-left: 1.5rem !important;
}
.m-5 {
margin: 3rem !important;
}
.mt-5,
.my-5 {
margin-top: 3rem !important;
}
.mr-5,
.mx-5 {
margin-right: 3rem !important;
}
.mb-5,
.my-5 {
margin-bottom: 3rem !important;
}
.ml-5,
.mx-5 {
margin-left: 3rem !important;
}
.p-0 {
padding: 0 !important;
}
.pt-0,
.py-0 {
padding-top: 0 !important;
}
.pr-0,
.px-0 {
padding-right: 0 !important;
}
.pb-0,
.py-0 {
padding-bottom: 0 !important;
}
.pl-0,
.px-0 {
padding-left: 0 !important;
}
.p-1 {
padding: 0.25rem !important;
}
.pt-1,
.py-1 {
padding-top: 0.25rem !important;
}
.pr-1,
.px-1 {
padding-right: 0.25rem !important;
}
.pb-1,
.py-1 {
padding-bottom: 0.25rem !important;
}
.pl-1,
.px-1 {
padding-left: 0.25rem !important;
}
.p-2 {
padding: 0.5rem !important;
}
.pt-2,
.py-2 {
padding-top: 0.5rem !important;
}
.pr-2,
.px-2 {
padding-right: 0.5rem !important;
}
.pb-2,
.py-2 {
padding-bottom: 0.5rem !important;
}
.pl-2,
.px-2 {
padding-left: 0.5rem !important;
}
.p-3 {
padding: 1rem !important;
}
.pt-3,
.py-3 {
padding-top: 1rem !important;
}
.pr-3,
.px-3 {
padding-right: 1rem !important;
}
.pb-3,
.py-3 {
padding-bottom: 1rem !important;
}
.pl-3,
.px-3 {
padding-left: 1rem !important;
}
.p-4 {
padding: 1.5rem !important;
}
.pt-4,
.py-4 {
padding-top: 1.5rem !important;
}
.pr-4,
.px-4 {
padding-right: 1.5rem !important;
}
.pb-4,
.py-4 {
padding-bottom: 1.5rem !important;
}
.pl-4,
.px-4 {
padding-left: 1.5rem !important;
}
.p-5 {
padding: 3rem !important;
}
.pt-5,
.py-5 {
padding-top: 3rem !important;
}
.pr-5,
.px-5 {
padding-right: 3rem !important;
}
.pb-5,
.py-5 {
padding-bottom: 3rem !important;
}
.pl-5,
.px-5 {
padding-left: 3rem !important;
}
.m-auto {
margin: auto !important;
}
.mt-auto,
.my-auto {
margin-top: auto !important;
}
.mr-auto,
.mx-auto {
margin-right: auto !important;
}
.mb-auto,
.my-auto {
margin-bottom: auto !important;
}
.ml-auto,
.mx-auto {
margin-left: auto !important;
}
@media (min-width: 576px) {
.m-sm-0 {
margin: 0 !important;
}
.mt-sm-0,
.my-sm-0 {
margin-top: 0 !important;
}
.mr-sm-0,
.mx-sm-0 {
margin-right: 0 !important;
}
.mb-sm-0,
.my-sm-0 {
margin-bottom: 0 !important;
}
.ml-sm-0,
.mx-sm-0 {
margin-left: 0 !important;
}
.m-sm-1 {
margin: 0.25rem !important;
}
.mt-sm-1,
.my-sm-1 {
margin-top: 0.25rem !important;
}
.mr-sm-1,
.mx-sm-1 {
margin-right: 0.25rem !important;
}
.mb-sm-1,
.my-sm-1 {
margin-bottom: 0.25rem !important;
}
.ml-sm-1,
.mx-sm-1 {
margin-left: 0.25rem !important;
}
.m-sm-2 {
margin: 0.5rem !important;
}
.mt-sm-2,
.my-sm-2 {
margin-top: 0.5rem !important;
}
.mr-sm-2,
.mx-sm-2 {
margin-right: 0.5rem !important;
}
.mb-sm-2,
.my-sm-2 {
margin-bottom: 0.5rem !important;
}
.ml-sm-2,
.mx-sm-2 {
margin-left: 0.5rem !important;
}
.m-sm-3 {
margin: 1rem !important;
}
.mt-sm-3,
.my-sm-3 {
margin-top: 1rem !important;
}
.mr-sm-3,
.mx-sm-3 {
margin-right: 1rem !important;
}
.mb-sm-3,
.my-sm-3 {
margin-bottom: 1rem !important;
}
.ml-sm-3,
.mx-sm-3 {
margin-left: 1rem !important;
}
.m-sm-4 {
margin: 1.5rem !important;
}
.mt-sm-4,
.my-sm-4 {
margin-top: 1.5rem !important;
}
.mr-sm-4,
.mx-sm-4 {
margin-right: 1.5rem !important;
}
.mb-sm-4,
.my-sm-4 {
margin-bottom: 1.5rem !important;
}
.ml-sm-4,
.mx-sm-4 {
margin-left: 1.5rem !important;
}
.m-sm-5 {
margin: 3rem !important;
}
.mt-sm-5,
.my-sm-5 {
margin-top: 3rem !important;
}
.mr-sm-5,
.mx-sm-5 {
margin-right: 3rem !important;
}
.mb-sm-5,
.my-sm-5 {
margin-bottom: 3rem !important;
}
.ml-sm-5,
.mx-sm-5 {
margin-left: 3rem !important;
}
.p-sm-0 {
padding: 0 !important;
}
.pt-sm-0,
.py-sm-0 {
padding-top: 0 !important;
}
.pr-sm-0,
.px-sm-0 {
padding-right: 0 !important;
}
.pb-sm-0,
.py-sm-0 {
padding-bottom: 0 !important;
}
.pl-sm-0,
.px-sm-0 {
padding-left: 0 !important;
}
.p-sm-1 {
padding: 0.25rem !important;
}
.pt-sm-1,
.py-sm-1 {
padding-top: 0.25rem !important;
}
.pr-sm-1,
.px-sm-1 {
padding-right: 0.25rem !important;
}
.pb-sm-1,
.py-sm-1 {
padding-bottom: 0.25rem !important;
}
.pl-sm-1,
.px-sm-1 {
padding-left: 0.25rem !important;
}
.p-sm-2 {
padding: 0.5rem !important;
}
.pt-sm-2,
.py-sm-2 {
padding-top: 0.5rem !important;
}
.pr-sm-2,
.px-sm-2 {
padding-right: 0.5rem !important;
}
.pb-sm-2,
.py-sm-2 {
padding-bottom: 0.5rem !important;
}
.pl-sm-2,
.px-sm-2 {
padding-left: 0.5rem !important;
}
.p-sm-3 {
padding: 1rem !important;
}
.pt-sm-3,
.py-sm-3 {
padding-top: 1rem !important;
}
.pr-sm-3,
.px-sm-3 {
padding-right: 1rem !important;
}
.pb-sm-3,
.py-sm-3 {
padding-bottom: 1rem !important;
}
.pl-sm-3,
.px-sm-3 {
padding-left: 1rem !important;
}
.p-sm-4 {
padding: 1.5rem !important;
}
.pt-sm-4,
.py-sm-4 {
padding-top: 1.5rem !important;
}
.pr-sm-4,
.px-sm-4 {
padding-right: 1.5rem !important;
}
.pb-sm-4,
.py-sm-4 {
padding-bottom: 1.5rem !important;
}
.pl-sm-4,
.px-sm-4 {
padding-left: 1.5rem !important;
}
.p-sm-5 {
padding: 3rem !important;
}
.pt-sm-5,
.py-sm-5 {
padding-top: 3rem !important;
}
.pr-sm-5,
.px-sm-5 {
padding-right: 3rem !important;
}
.pb-sm-5,
.py-sm-5 {
padding-bottom: 3rem !important;
}
.pl-sm-5,
.px-sm-5 {
padding-left: 3rem !important;
}
.m-sm-auto {
margin: auto !important;
}
.mt-sm-auto,
.my-sm-auto {
margin-top: auto !important;
}
.mr-sm-auto,
.mx-sm-auto {
margin-right: auto !important;
}
.mb-sm-auto,
.my-sm-auto {
margin-bottom: auto !important;
}
.ml-sm-auto,
.mx-sm-auto {
margin-left: auto !important;
}
}
@media (min-width: 768px) {
.m-md-0 {
margin: 0 !important;
}
.mt-md-0,
.my-md-0 {
margin-top: 0 !important;
}
.mr-md-0,
.mx-md-0 {
margin-right: 0 !important;
}
.mb-md-0,
.my-md-0 {
margin-bottom: 0 !important;
}
.ml-md-0,
.mx-md-0 {
margin-left: 0 !important;
}
.m-md-1 {
margin: 0.25rem !important;
}
.mt-md-1,
.my-md-1 {
margin-top: 0.25rem !important;
}
.mr-md-1,
.mx-md-1 {
margin-right: 0.25rem !important;
}
.mb-md-1,
.my-md-1 {
margin-bottom: 0.25rem !important;
}
.ml-md-1,
.mx-md-1 {
margin-left: 0.25rem !important;
}
.m-md-2 {
margin: 0.5rem !important;
}
.mt-md-2,
.my-md-2 {
margin-top: 0.5rem !important;
}
.mr-md-2,
.mx-md-2 {
margin-right: 0.5rem !important;
}
.mb-md-2,
.my-md-2 {
margin-bottom: 0.5rem !important;
}
.ml-md-2,
.mx-md-2 {
margin-left: 0.5rem !important;
}
.m-md-3 {
margin: 1rem !important;
}
.mt-md-3,
.my-md-3 {
margin-top: 1rem !important;
}
.mr-md-3,
.mx-md-3 {
margin-right: 1rem !important;
}
.mb-md-3,
.my-md-3 {
margin-bottom: 1rem !important;
}
.ml-md-3,
.mx-md-3 {
margin-left: 1rem !important;
}
.m-md-4 {
margin: 1.5rem !important;
}
.mt-md-4,
.my-md-4 {
margin-top: 1.5rem !important;
}
.mr-md-4,
.mx-md-4 {
margin-right: 1.5rem !important;
}
.mb-md-4,
.my-md-4 {
margin-bottom: 1.5rem !important;
}
.ml-md-4,
.mx-md-4 {
margin-left: 1.5rem !important;
}
.m-md-5 {
margin: 3rem !important;
}
.mt-md-5,
.my-md-5 {
margin-top: 3rem !important;
}
.mr-md-5,
.mx-md-5 {
margin-right: 3rem !important;
}
.mb-md-5,
.my-md-5 {
margin-bottom: 3rem !important;
}
.ml-md-5,
.mx-md-5 {
margin-left: 3rem !important;
}
.p-md-0 {
padding: 0 !important;
}
.pt-md-0,
.py-md-0 {
padding-top: 0 !important;
}
.pr-md-0,
.px-md-0 {
padding-right: 0 !important;
}
.pb-md-0,
.py-md-0 {
padding-bottom: 0 !important;
}
.pl-md-0,
.px-md-0 {
padding-left: 0 !important;
}
.p-md-1 {
padding: 0.25rem !important;
}
.pt-md-1,
.py-md-1 {
padding-top: 0.25rem !important;
}
.pr-md-1,
.px-md-1 {
padding-right: 0.25rem !important;
}
.pb-md-1,
.py-md-1 {
padding-bottom: 0.25rem !important;
}
.pl-md-1,
.px-md-1 {
padding-left: 0.25rem !important;
}
.p-md-2 {
padding: 0.5rem !important;
}
.pt-md-2,
.py-md-2 {
padding-top: 0.5rem !important;
}
.pr-md-2,
.px-md-2 {
padding-right: 0.5rem !important;
}
.pb-md-2,
.py-md-2 {
padding-bottom: 0.5rem !important;
}
.pl-md-2,
.px-md-2 {
padding-left: 0.5rem !important;
}
.p-md-3 {
padding: 1rem !important;
}
.pt-md-3,
.py-md-3 {
padding-top: 1rem !important;
}
.pr-md-3,
.px-md-3 {
padding-right: 1rem !important;
}
.pb-md-3,
.py-md-3 {
padding-bottom: 1rem !important;
}
.pl-md-3,
.px-md-3 {
padding-left: 1rem !important;
}
.p-md-4 {
padding: 1.5rem !important;
}
.pt-md-4,
.py-md-4 {
padding-top: 1.5rem !important;
}
.pr-md-4,
.px-md-4 {
padding-right: 1.5rem !important;
}
.pb-md-4,
.py-md-4 {
padding-bottom: 1.5rem !important;
}
.pl-md-4,
.px-md-4 {
padding-left: 1.5rem !important;
}
.p-md-5 {
padding: 3rem !important;
}
.pt-md-5,
.py-md-5 {
padding-top: 3rem !important;
}
.pr-md-5,
.px-md-5 {
padding-right: 3rem !important;
}
.pb-md-5,
.py-md-5 {
padding-bottom: 3rem !important;
}
.pl-md-5,
.px-md-5 {
padding-left: 3rem !important;
}
.m-md-auto {
margin: auto !important;
}
.mt-md-auto,
.my-md-auto {
margin-top: auto !important;
}
.mr-md-auto,
.mx-md-auto {
margin-right: auto !important;
}
.mb-md-auto,
.my-md-auto {
margin-bottom: auto !important;
}
.ml-md-auto,
.mx-md-auto {
margin-left: auto !important;
}
}
@media (min-width: 992px) {
.m-lg-0 {
margin: 0 !important;
}
.mt-lg-0,
.my-lg-0 {
margin-top: 0 !important;
}
.mr-lg-0,
.mx-lg-0 {
margin-right: 0 !important;
}
.mb-lg-0,
.my-lg-0 {
margin-bottom: 0 !important;
}
.ml-lg-0,
.mx-lg-0 {
margin-left: 0 !important;
}
.m-lg-1 {
margin: 0.25rem !important;
}
.mt-lg-1,
.my-lg-1 {
margin-top: 0.25rem !important;
}
.mr-lg-1,
.mx-lg-1 {
margin-right: 0.25rem !important;
}
.mb-lg-1,
.my-lg-1 {
margin-bottom: 0.25rem !important;
}
.ml-lg-1,
.mx-lg-1 {
margin-left: 0.25rem !important;
}
.m-lg-2 {
margin: 0.5rem !important;
}
.mt-lg-2,
.my-lg-2 {
margin-top: 0.5rem !important;
}
.mr-lg-2,
.mx-lg-2 {
margin-right: 0.5rem !important;
}
.mb-lg-2,
.my-lg-2 {
margin-bottom: 0.5rem !important;
}
.ml-lg-2,
.mx-lg-2 {
margin-left: 0.5rem !important;
}
.m-lg-3 {
margin: 1rem !important;
}
.mt-lg-3,
.my-lg-3 {
margin-top: 1rem !important;
}
.mr-lg-3,
.mx-lg-3 {
margin-right: 1rem !important;
}
.mb-lg-3,
.my-lg-3 {
margin-bottom: 1rem !important;
}
.ml-lg-3,
.mx-lg-3 {
margin-left: 1rem !important;
}
.m-lg-4 {
margin: 1.5rem !important;
}
.mt-lg-4,
.my-lg-4 {
margin-top: 1.5rem !important;
}
.mr-lg-4,
.mx-lg-4 {
margin-right: 1.5rem !important;
}
.mb-lg-4,
.my-lg-4 {
margin-bottom: 1.5rem !important;
}
.ml-lg-4,
.mx-lg-4 {
margin-left: 1.5rem !important;
}
.m-lg-5 {
margin: 3rem !important;
}
.mt-lg-5,
.my-lg-5 {
margin-top: 3rem !important;
}
.mr-lg-5,
.mx-lg-5 {
margin-right: 3rem !important;
}
.mb-lg-5,
.my-lg-5 {
margin-bottom: 3rem !important;
}
.ml-lg-5,
.mx-lg-5 {
margin-left: 3rem !important;
}
.p-lg-0 {
padding: 0 !important;
}
.pt-lg-0,
.py-lg-0 {
padding-top: 0 !important;
}
.pr-lg-0,
.px-lg-0 {
padding-right: 0 !important;
}
.pb-lg-0,
.py-lg-0 {
padding-bottom: 0 !important;
}
.pl-lg-0,
.px-lg-0 {
padding-left: 0 !important;
}
.p-lg-1 {
padding: 0.25rem !important;
}
.pt-lg-1,
.py-lg-1 {
padding-top: 0.25rem !important;
}
.pr-lg-1,
.px-lg-1 {
padding-right: 0.25rem !important;
}
.pb-lg-1,
.py-lg-1 {
padding-bottom: 0.25rem !important;
}
.pl-lg-1,
.px-lg-1 {
padding-left: 0.25rem !important;
}
.p-lg-2 {
padding: 0.5rem !important;
}
.pt-lg-2,
.py-lg-2 {
padding-top: 0.5rem !important;
}
.pr-lg-2,
.px-lg-2 {
padding-right: 0.5rem !important;
}
.pb-lg-2,
.py-lg-2 {
padding-bottom: 0.5rem !important;
}
.pl-lg-2,
.px-lg-2 {
padding-left: 0.5rem !important;
}
.p-lg-3 {
padding: 1rem !important;
}
.pt-lg-3,
.py-lg-3 {
padding-top: 1rem !important;
}
.pr-lg-3,
.px-lg-3 {
padding-right: 1rem !important;
}
.pb-lg-3,
.py-lg-3 {
padding-bottom: 1rem !important;
}
.pl-lg-3,
.px-lg-3 {
padding-left: 1rem !important;
}
.p-lg-4 {
padding: 1.5rem !important;
}
.pt-lg-4,
.py-lg-4 {
padding-top: 1.5rem !important;
}
.pr-lg-4,
.px-lg-4 {
padding-right: 1.5rem !important;
}
.pb-lg-4,
.py-lg-4 {
padding-bottom: 1.5rem !important;
}
.pl-lg-4,
.px-lg-4 {
padding-left: 1.5rem !important;
}
.p-lg-5 {
padding: 3rem !important;
}
.pt-lg-5,
.py-lg-5 {
padding-top: 3rem !important;
}
.pr-lg-5,
.px-lg-5 {
padding-right: 3rem !important;
}
.pb-lg-5,
.py-lg-5 {
padding-bottom: 3rem !important;
}
.pl-lg-5,
.px-lg-5 {
padding-left: 3rem !important;
}
.m-lg-auto {
margin: auto !important;
}
.mt-lg-auto,
.my-lg-auto {
margin-top: auto !important;
}
.mr-lg-auto,
.mx-lg-auto {
margin-right: auto !important;
}
.mb-lg-auto,
.my-lg-auto {
margin-bottom: auto !important;
}
.ml-lg-auto,
.mx-lg-auto {
margin-left: auto !important;
}
}
@media (min-width: 1200px) {
.m-xl-0 {
margin: 0 !important;
}
.mt-xl-0,
.my-xl-0 {
margin-top: 0 !important;
}
.mr-xl-0,
.mx-xl-0 {
margin-right: 0 !important;
}
.mb-xl-0,
.my-xl-0 {
margin-bottom: 0 !important;
}
.ml-xl-0,
.mx-xl-0 {
margin-left: 0 !important;
}
.m-xl-1 {
margin: 0.25rem !important;
}
.mt-xl-1,
.my-xl-1 {
margin-top: 0.25rem !important;
}
.mr-xl-1,
.mx-xl-1 {
margin-right: 0.25rem !important;
}
.mb-xl-1,
.my-xl-1 {
margin-bottom: 0.25rem !important;
}
.ml-xl-1,
.mx-xl-1 {
margin-left: 0.25rem !important;
}
.m-xl-2 {
margin: 0.5rem !important;
}
.mt-xl-2,
.my-xl-2 {
margin-top: 0.5rem !important;
}
.mr-xl-2,
.mx-xl-2 {
margin-right: 0.5rem !important;
}
.mb-xl-2,
.my-xl-2 {
margin-bottom: 0.5rem !important;
}
.ml-xl-2,
.mx-xl-2 {
margin-left: 0.5rem !important;
}
.m-xl-3 {
margin: 1rem !important;
}
.mt-xl-3,
.my-xl-3 {
margin-top: 1rem !important;
}
.mr-xl-3,
.mx-xl-3 {
margin-right: 1rem !important;
}
.mb-xl-3,
.my-xl-3 {
margin-bottom: 1rem !important;
}
.ml-xl-3,
.mx-xl-3 {
margin-left: 1rem !important;
}
.m-xl-4 {
margin: 1.5rem !important;
}
.mt-xl-4,
.my-xl-4 {
margin-top: 1.5rem !important;
}
.mr-xl-4,
.mx-xl-4 {
margin-right: 1.5rem !important;
}
.mb-xl-4,
.my-xl-4 {
margin-bottom: 1.5rem !important;
}
.ml-xl-4,
.mx-xl-4 {
margin-left: 1.5rem !important;
}
.m-xl-5 {
margin: 3rem !important;
}
.mt-xl-5,
.my-xl-5 {
margin-top: 3rem !important;
}
.mr-xl-5,
.mx-xl-5 {
margin-right: 3rem !important;
}
.mb-xl-5,
.my-xl-5 {
margin-bottom: 3rem !important;
}
.ml-xl-5,
.mx-xl-5 {
margin-left: 3rem !important;
}
.p-xl-0 {
padding: 0 !important;
}
.pt-xl-0,
.py-xl-0 {
padding-top: 0 !important;
}
.pr-xl-0,
.px-xl-0 {
padding-right: 0 !important;
}
.pb-xl-0,
.py-xl-0 {
padding-bottom: 0 !important;
}
.pl-xl-0,
.px-xl-0 {
padding-left: 0 !important;
}
.p-xl-1 {
padding: 0.25rem !important;
}
.pt-xl-1,
.py-xl-1 {
padding-top: 0.25rem !important;
}
.pr-xl-1,
.px-xl-1 {
padding-right: 0.25rem !important;
}
.pb-xl-1,
.py-xl-1 {
padding-bottom: 0.25rem !important;
}
.pl-xl-1,
.px-xl-1 {
padding-left: 0.25rem !important;
}
.p-xl-2 {
padding: 0.5rem !important;
}
.pt-xl-2,
.py-xl-2 {
padding-top: 0.5rem !important;
}
.pr-xl-2,
.px-xl-2 {
padding-right: 0.5rem !important;
}
.pb-xl-2,
.py-xl-2 {
padding-bottom: 0.5rem !important;
}
.pl-xl-2,
.px-xl-2 {
padding-left: 0.5rem !important;
}
.p-xl-3 {
padding: 1rem !important;
}
.pt-xl-3,
.py-xl-3 {
padding-top: 1rem !important;
}
.pr-xl-3,
.px-xl-3 {
padding-right: 1rem !important;
}
.pb-xl-3,
.py-xl-3 {
padding-bottom: 1rem !important;
}
.pl-xl-3,
.px-xl-3 {
padding-left: 1rem !important;
}
.p-xl-4 {
padding: 1.5rem !important;
}
.pt-xl-4,
.py-xl-4 {
padding-top: 1.5rem !important;
}
.pr-xl-4,
.px-xl-4 {
padding-right: 1.5rem !important;
}
.pb-xl-4,
.py-xl-4 {
padding-bottom: 1.5rem !important;
}
.pl-xl-4,
.px-xl-4 {
padding-left: 1.5rem !important;
}
.p-xl-5 {
padding: 3rem !important;
}
.pt-xl-5,
.py-xl-5 {
padding-top: 3rem !important;
}
.pr-xl-5,
.px-xl-5 {
padding-right: 3rem !important;
}
.pb-xl-5,
.py-xl-5 {
padding-bottom: 3rem !important;
}
.pl-xl-5,
.px-xl-5 {
padding-left: 3rem !important;
}
.m-xl-auto {
margin: auto !important;
}
.mt-xl-auto,
.my-xl-auto {
margin-top: auto !important;
}
.mr-xl-auto,
.mx-xl-auto {
margin-right: auto !important;
}
.mb-xl-auto,
.my-xl-auto {
margin-bottom: auto !important;
}
.ml-xl-auto,
.mx-xl-auto {
margin-left: auto !important;
}
}
.text-justify {
text-align: justify !important;
}
.text-nowrap {
white-space: nowrap !important;
}
.text-truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.text-left {
text-align: left !important;
}
.text-right {
text-align: right !important;
}
.text-center {
text-align: center !important;
}
@media (min-width: 576px) {
.text-sm-left {
text-align: left !important;
}
.text-sm-right {
text-align: right !important;
}
.text-sm-center {
text-align: center !important;
}
}
@media (min-width: 768px) {
.text-md-left {
text-align: left !important;
}
.text-md-right {
text-align: right !important;
}
.text-md-center {
text-align: center !important;
}
}
@media (min-width: 992px) {
.text-lg-left {
text-align: left !important;
}
.text-lg-right {
text-align: right !important;
}
.text-lg-center {
text-align: center !important;
}
}
@media (min-width: 1200px) {
.text-xl-left {
text-align: left !important;
}
.text-xl-right {
text-align: right !important;
}
.text-xl-center {
text-align: center !important;
}
}
.text-lowercase {
text-transform: lowercase !important;
}
.text-uppercase {
text-transform: uppercase !important;
}
.text-capitalize {
text-transform: capitalize !important;
}
.font-weight-light {
font-weight: 300 !important;
}
.font-weight-normal {
font-weight: 400 !important;
}
.font-weight-bold {
font-weight: 700 !important;
}
.font-italic {
font-style: italic !important;
}
.text-white {
color: #fff !important;
}
.text-primary {
color: #007bff !important;
}
a.text-primary:hover, a.text-primary:focus {
color: #0062cc !important;
}
.text-secondary {
color: #6c757d !important;
}
a.text-secondary:hover, a.text-secondary:focus {
color: #545b62 !important;
}
.text-success {
color: #28a745 !important;
}
a.text-success:hover, a.text-success:focus {
color: #1e7e34 !important;
}
.text-info {
color: #17a2b8 !important;
}
a.text-info:hover, a.text-info:focus {
color: #117a8b !important;
}
.text-warning {
color: #ffc107 !important;
}
a.text-warning:hover, a.text-warning:focus {
color: #d39e00 !important;
}
.text-danger {
color: #dc3545 !important;
}
a.text-danger:hover, a.text-danger:focus {
color: #bd2130 !important;
}
.text-light {
color: #f8f9fa !important;
}
a.text-light:hover, a.text-light:focus {
color: #dae0e5 !important;
}
.text-dark {
color: #343a40 !important;
}
a.text-dark:hover, a.text-dark:focus {
color: #1d2124 !important;
}
.text-muted {
color: #6c757d !important;
}
.text-hide {
font: 0/0 a;
color: transparent;
text-shadow: none;
background-color: transparent;
border: 0;
}
.visible {
visibility: visible !important;
}
.invisible {
visibility: hidden !important;
}
@media print {
*,
*::before,
*::after {
text-shadow: none !important;
box-shadow: none !important;
}
a:not(.btn) {
text-decoration: underline;
}
abbr[title]::after {
content: " (" attr(title) ")";
}
pre {
white-space: pre-wrap !important;
}
pre,
blockquote {
border: 1px solid #999;
page-break-inside: avoid;
}
thead {
display: table-header-group;
}
tr,
img {
page-break-inside: avoid;
}
p,
h2,
h3 {
orphans: 3;
widows: 3;
}
h2,
h3 {
page-break-after: avoid;
}
@page {
size: a3;
}
body {
min-width: 992px !important;
}
.container {
min-width: 992px !important;
}
.navbar {
display: none;
}
.badge {
border: 1px solid #000;
}
.table {
border-collapse: collapse !important;
}
.table td,
.table th {
background-color: #fff !important;
}
.table-bordered th,
.table-bordered td {
border: 1px solid #ddd !important;
}
}
/*# sourceMappingURL=bootstrap.css.map */
================================================
FILE: assets/css/styles.css
================================================
.card {
margin-bottom: 1.0em;
}
.btn {
margin: 5px;
}
.zoom-effect {
-webkit-transition: 0.6s ease;
}
.zoom-effect:hover {
-webkit-transform: scale(1.05);
}
.iframe-terminal {
width: 100%;
height: 400px;
}
.filter-button {
margin: 2px;
}
================================================
FILE: assets/database.sql
================================================
-- phpMyAdmin SQL Dump
-- version 4.9.0.1
-- https://www.phpmyadmin.net/
--
-- Host: 127.0.0.1
-- Tempo de geração: 05-Jul-2019 às 22:24
-- Versão do servidor: 10.3.16-MariaDB
-- versão do PHP: 7.3.6
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Banco de dados: `kali`
--
-- --------------------------------------------------------
--
-- Estrutura da tabela `commands`
--
CREATE TABLE `commands` (
`id` int(11) NOT NULL,
`name` varchar(80) DEFAULT NULL,
`description` text DEFAULT NULL,
`examples` text DEFAULT NULL,
`tool` int(11) DEFAULT NULL,
`type` varchar(30) DEFAULT NULL,
`command` text DEFAULT NULL,
`example` varchar(150) DEFAULT NULL,
`sudo` int(1) DEFAULT NULL,
`category` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Extraindo dados da tabela `commands`
--
INSERT INTO `commands` (`id`, `name`, `description`, `examples`, `tool`, `type`, `command`, `example`, `sudo`, `category`) VALUES
(1, 'Scan specific ports', NULL, 'nmap -p 80,443 8.8.8.8', 1, 'input', '-p', 'Specific: 80,443 OR Range: 1-65536', NULL, 'PORT SPECIFICATION AND SCAN ORDER'),
(28, 'Ping Scan - disable port scan', NULL, NULL, 1, 'checkbox', '-sL', NULL, NULL, 'HOST DISCOVERY'),
(29, 'Skip host discovery', NULL, NULL, 1, 'checkbox', '-Pn', NULL, NULL, 'HOST DISCOVERY'),
(30, 'Trace hop path to each host', NULL, NULL, 1, 'checkbox', '--traceroute', NULL, NULL, 'HOST DISCOVERY'),
(31, 'Use OS\'s DNS resolver', NULL, NULL, 1, 'checkbox', '--system-dns', NULL, NULL, 'HOST DISCOVERY'),
(32, 'Exclude hosts/networks', NULL, NULL, 1, 'input', '--exclude', 'Example: 192.168.0.1', NULL, 'TARGET SPECIFICATION'),
(33, 'Enable OS detection', NULL, NULL, 1, 'checkbox', '-O', NULL, NULL, 'OS DETECTION'),
(34, 'IP protocol scan', NULL, NULL, 1, 'checkbox', '-sO', NULL, NULL, 'SCAN TECHNIQUES'),
(35, 'FTP bounce scan', NULL, NULL, 1, 'checkbox', '-b', NULL, NULL, 'SCAN TECHNIQUES'),
(36, 'Exclude the specified ports from scanning', NULL, NULL, 1, 'input', '--exclude-ports', 'Specific: 80,443 OR Range: 1-65536', NULL, 'PORT SPECIFICATION AND SCAN ORDER'),
(37, 'Scan 100 most common ports', NULL, NULL, 1, 'checkbox', '-F', NULL, NULL, 'PORT SPECIFICATION AND SCAN ORDER'),
(40, 'Service detection (Standard)', NULL, NULL, 1, 'checkbox', '-sV', NULL, NULL, 'SERVICE/VERSION DETECTION'),
(42, 'OS detection, version, script scanning, and traceroute', NULL, NULL, 1, 'checkbox', '-A', NULL, NULL, 'MISC'),
(43, 'Print version number', NULL, NULL, 1, 'show', '-V', NULL, NULL, 'MISC'),
(44, 'Print this help summary page.', NULL, NULL, 1, 'show', '-h', NULL, NULL, 'MISC'),
(45, 'Enable IPv6 scanning', NULL, NULL, 1, 'checkbox', '-6', NULL, NULL, 'MISC'),
(47, 'UDP Scan', NULL, NULL, 1, 'checkbox', '-sU', NULL, NULL, 'SCAN TECHNIQUES'),
(48, 'Scan for vulnerabilities', NULL, NULL, 1, 'checkbox', '-sS -sC -Pn --script vuln', 'nmap -sS -sC -Pn --script vuln scanme.nmap.org ', NULL, NULL),
(49, 'Scan for exploits', NULL, NULL, 1, 'checkbox', '-Pn -sS -sC --script exploit', 'nmap -Pn -sS -sC --script exploit scanme.nmap.org ', NULL, NULL),
(50, 'Scan to test DoS attack vulnerability', NULL, NULL, 1, 'checkbox', '-Pn -sS -sC --script dos', 'nmap -Pn -sS -sC --script dos scanme.nmap.org ', NULL, NULL),
(52, 'Perform DoS attacks with a simulator', NULL, NULL, 1, 'checkbox', '--max-parallelism 750 -Pn --script http-slowloris --script-args http-slowloris.runforever=true', 'nmap --max-parallelism 750 -Pn --script http-slowloris --script-args http-slowloris.runforever=true scanme.nmap.org', NULL, NULL),
(53, 'Find subdomains', NULL, NULL, 1, 'checkbox', '-p 80 --script dns-brute.nse', 'nmap -p 80 --script dns-brute.nse vulnweb.com', NULL, NULL),
(54, 'Scan all 65535 ports', NULL, NULL, 1, 'checkbox', '-p-', NULL, NULL, NULL),
(55, 'Scan using TCP connect', NULL, NULL, 1, 'checkbox', '-sT', NULL, NULL, 'SCAN TECHNIQUES'),
(56, 'Scan UDP ports', NULL, NULL, 1, 'checkbox', '-sU -p 123,161,162', NULL, NULL, NULL),
(57, 'Service detection (Agressive)', NULL, NULL, 1, 'checkbox', '--version-intensity 5', NULL, NULL, 'SERVICE/VERSION DETECTION'),
(58, 'Service detection (Lighter)', NULL, NULL, 1, 'checkbox', '-sV --version-intensity 0', NULL, NULL, 'SERVICE/VERSION DETECTION'),
(59, 'Scan using default safe scripts', NULL, NULL, 1, 'checkbox', '-sV -sC', NULL, NULL, NULL),
(60, 'Scan for UDP DDOS reflectors', NULL, NULL, 1, 'checkbox', '–sU –A –PN –n –pU:19,53,123,161 –script=ntp-monlist,dns-recursion,snmp-sysdescr', NULL, NULL, NULL),
(61, 'Gather page titles from HTTP services', NULL, NULL, 1, 'checkbox', '--script=http-title', NULL, NULL, 'HTTP Service Information'),
(62, 'Get HTTP headers of web services', NULL, NULL, 1, 'checkbox', '--script=http-headers', NULL, NULL, 'HTTP Service Information'),
(63, 'Find web apps from known paths', NULL, NULL, 1, 'checkbox', '--script=http-enum', NULL, NULL, NULL),
(64, 'Only show open (or possibly open) ports', NULL, NULL, 1, 'checkbox', '--open', NULL, NULL, NULL),
(65, 'Show host interfaces and routes', NULL, NULL, 1, 'checkbox', '--iflist', NULL, NULL, NULL),
(66, 'Scan using IP protocol ping', NULL, NULL, 1, 'checkbox', '-PO', NULL, NULL, NULL),
(67, 'Scan using UDP ping', NULL, NULL, 1, 'checkbox', '-PU', NULL, NULL, NULL),
(68, 'TCP Fin scan to check firewall', NULL, NULL, 1, 'checkbox', '-sF', NULL, NULL, 'Scan a firewall for security weakness'),
(69, 'TCP Xmas scan to check firewall', NULL, NULL, 1, 'checkbox', '-sX', NULL, NULL, 'Scan a firewall for security weakness'),
(70, 'TCP Null Scan to fool a firewall to generate a response', NULL, NULL, 1, 'checkbox', '-sN', NULL, NULL, 'Scan a firewall for security weakness'),
(71, 'Perform a DNS TLD expansion', NULL, NULL, 3, 'checkbox', '-t', NULL, NULL, NULL),
(72, 'Perform a DNS brute force', NULL, NULL, 3, 'checkbox', '-c', NULL, NULL, NULL),
(73, 'Perform a DNS reverse query', NULL, NULL, 3, 'checkbox', '-n', NULL, NULL, NULL),
(74, 'Use this DNS server', NULL, NULL, 3, 'input', '-e', 'Set a DNS server', NULL, NULL),
(75, 'Limit the number of results to work with', NULL, NULL, 3, 'input', '-l', 'Google goes from 100 to 100', NULL, NULL),
(76, 'Start in result number', NULL, NULL, 3, 'input', '-s', 'Default 0', NULL, NULL),
(77, 'Data source', NULL, NULL, 3, 'input', '-b', 'Ex.: google,bing,linkedin', NULL, NULL),
(78, 'Use this source address', NULL, NULL, 8, 'input', '-S', NULL, NULL, NULL),
(79, 'Limit time to wait per try', NULL, NULL, 8, 'input', '-t', NULL, NULL, NULL),
(80, 'Don\'t query IPv6 servers', NULL, NULL, 8, 'checkbox', '-4', NULL, NULL, NULL),
(81, 'Show all details and informations', NULL, NULL, 8, 'checkbox', '-v', NULL, NULL, NULL),
(82, 'Retry limit', NULL, NULL, 8, 'input', '-r', 'Ex: 1', NULL, NULL),
(83, 'Specific the register type', NULL, NULL, 8, 'input', '-q', 'Ex: A, AAA, MX, NS, TXT', NULL, NULL),
(84, 'Enable overview of received answers', NULL, NULL, 8, 'checkbox', '-o', NULL, NULL, NULL),
(85, 'Enable negative cache', NULL, NULL, 8, 'checkbox', '-C', NULL, NULL, NULL),
(86, 'Disable local caching', NULL, NULL, 8, 'checkbox', '-c', NULL, NULL, NULL),
(87, 'Verify host name and search for virtual hosts', NULL, NULL, 3, 'checkbox', '-v', NULL, NULL, NULL),
(88, 'Search', NULL, NULL, 15, 'input', 'search', 'To use this, clean target\'s field.', NULL, NULL),
(90, 'Search emails with the local-part', NULL, NULL, 15, 'checkbox', '--local-part', NULL, NULL, NULL),
(91, 'Search emails with the password', NULL, NULL, 15, 'checkbox', '--password', NULL, NULL, NULL),
(92, 'Search emails with the domain', NULL, NULL, 15, 'checkbox', '--domain', NULL, NULL, NULL),
(93, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(94, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(95, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(96, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-- --------------------------------------------------------
--
-- Estrutura da tabela `reports`
--
CREATE TABLE `reports` (
`id` int(11) NOT NULL,
`name` varchar(100) DEFAULT NULL,
`tools` varchar(100) DEFAULT NULL,
`command` varchar(500) DEFAULT NULL,
`output` text DEFAULT NULL,
`solution` text DEFAULT NULL,
`dataHour` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Extraindo dados da tabela `reports`
--
INSERT INTO `reports` (`id`, `name`, `tools`, `command`, `output`, `solution`, `dataHour`) VALUES
(23, 'Teste', 'Nmap: the Network Mapper', 'nmap -A localhost', '[sudo] senha para kali: Starting Nmap 7.70 ( https://nmap.org ) at 2019-06-28 16:26 -03\nNmap scan report for localhost (127.0.0.1)\nHost is up (0.000060s latency).\nOther addresses for localhost (not scanned): ::1\nNot shown: 998 closed ports\nPORT STATE SERVICE VERSION\n22/tcp open ssh OpenSSH 7.9p1 Debian 10 (protocol 2.0)\n| ssh-hostkey: \n| 2048 93:c0:bd:e9:89:88:14:ba:0c:a0:a6:52:cb:a8:2e:0e (RSA)\n| 256 6c:81:1c:f9:e4:c0:7d:98:ea:8b:f4:41:58:ad:0e:75 (ECDSA)\n|_ 256 55:08:ac:7c:6f:8f:0d:9c:c1:bf:e7:ae:1f:f8:eb:81 (ED25519)\n80/tcp open http nginx 1.14.2\n|_http-server-header: nginx/1.14.2\n|_http-title: Welcome to nginx!\nDevice type: general purpose\nRunning: Linux 3.X\nOS CPE: cpe:/o:linux:linux_kernel:3\nOS details: Linux 3.7 - 3.10\nNetwork Distance: 0 hops\nService Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel\n\nOS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .\nNmap done: 1 IP address (1 host up) scanned in 11.97 seconds\n', 'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using \'Content here, content here\', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for \'lorem ipsum\' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).\r\n\r\n', '2019-06-28 16:27:13'),
(60, 'theHarvester', 'Gmail - Pesquisa de e-mails', 'python /home/kali/Downloads/theHarvester/theHarvester.py -b google -l 50 -d gmail.com', '[-] Searching in Google:\n Searching 0 results...\n\n[+] Emails found:\n------------------\nexample@gmail.com\nexamp1e@gmail.com\nfolha.campinas@gmail.com\nprodutividade.coop.rj@gmail.com\npereirabarbosa.joao@gmail.com\nhello@gmail.com\nhumoristarudy@gmail.com\naugustolessa.rj@gmail.com\nmaria.nazareth.52@gmail.com\nedilson@gmail.com\nselecaoll2017@gmail.com\nusername@gmail.com\nquermesse.restaurante@gmail.com\npickalimentos@gmail.com\nsucuricleanups2@gmail.com\nflaviag.neide@gmail.com\nAmazonasautomoveis@gmail.com\nAmazonasautomoveis@gmail.com\nilankriger@gmail.com\n2606iolanda@gmail.com\npousadatocadosursos@gmail.com\nadrientwu@gmail.com\nsniprosperidadevilasonia@gmail.com\nbeechamanda@gmail.com\njohn.doe@gmail.com\njohndoe@gmail.com\nmagi.tonis@gmail.com\ngustavo.brafman@gmail.com\nmfatima.silva22@gmail.com\nlmgrh1@gmail.com\nmarliquantica@gmail.com\npatimezzomo@gmail.com\nrefrig.ar.nilson@gmail.com\nneedessentials1@gmail.com\nneeraj.knit06@gmail.com\nJennyseomarketing010@gmail.com\njennyseomarketing010@gmail.com\njeanhtorres@gmail.com\nGuerillaClick@gmail.com\nguerillaclick@gmail.com\npousadacasadasfontes@gmail.com\nlucasgiovanny@gmail.com\nyourname@gmail.com\nyour.name@gmail.com\ny.o.u.r.n.a.m.e.@gmail.com\n11wcc.rio@gmail.com\nvfcadettes@gmail.com\nconveniadagremioviamao@gmail.com\nvovoanitagramado@gmail.com\nhotelkamomil@gmail.com\nchansookchoi@gmail.com\nxyz@mail.gmail.com\ncojacre@gmail.com\nrafabastos.1999@gmail.com\nggloriassousa@gmail.com\ninstitutoibrae@gmail.com\niaupe.carnaiba2019@gmail.com\nyourusername@gmail.com\n\n[+] Hosts found in search engines:\n------------------------------------\n172.217.30.5:www.gmail.com\n64.233.186.108:smtp.gmail.com\n64.233.190.108:imap.gmail.com\n', 'theHarvester is a great tool for collecting information from a particular host, with it it is possible to get a list of emails, subdomains, hosts, employee names, open ports, banners from different public sources, PGP keys and mapped information by SHODAN.\r\n\r\nFIX THIS \r\n\r\nThe information found by theHarvester is indexed in Internet pages. If you want to hide this content you need to identify in the source of this information.\r\nFor this, one can be applied techniques like Google Hacking to refine the search in search engines users by theHarvester.\r\n\r\nOnce the data source is identified, you can hide or delete the data, for example, from a social network. If it is a content of your own, such as a personal blog, just create a robots.txt file and hide the pages that have the information.\r\n
\r\n\r\n\r\nUSEFUL LINKS \r\n\r\n • Google Hacking Techniques \r\n • Best Practices robots.txt \r\n\r\n ', '2019-07-01 22:17:46'),
(62, 'Karma', 'Varredura example@gmail.com', 'karma target example@gmail.com', '[sudo] password for kali: [32m[+] starting search [00m\n[32m[+] 1/1 request email: example@gmail.com [00m\n[32m[+] analyzing results: [00m\n[32m[+] 60 results found in 2.80s [00m\n\n\n A J V T B Y 0 T 5\n C U F I N 1 Q G V\n P H R K A J C X M\n I G F 4 T G E M K\n T H J S U 2 G 1 9\n 8 B S B F W 0 R M\n 0 Z [1mK A R M A [0mA X\n W 2 V T A C L 1 Z\n Y 6 W G I V S 3 Z\n X S E 6 E C S V D\n G Q 7 B X N P U T\n A 1 L X F W V Y 5\n\n decoxviii\n 1.2.1\n\n+-------------------+----------------------------------+\n| Email | Password |\n+===================+==================================+\n| example@gmail.com | pokelion |\n| example@gmail.com | 89151321781 |\n| example@gmail.com | 123qwe321Ewq |\n| example@gmail.com | buzzman |\n| example@gmail.com | 123qwe321Ewq |\n| example@gmail.com | santiago |\n| example@gmail.com | cynthia |\n| example@gmail.com | bob |\n| Example@gmail.com | eclips1 |\n| example@gmail.com | 0987654321 |\n| example@gmail.com | abc123458 |\n| example@gmail.com | 790223 |\n| example@gmail.com | ep8c4600 |\n| example@gmail.com | 15032000 |\n| example@gmail.com | 20101997 |\n| example@gmail.com | sushi |\n| example@gmail.com | password |\n| example@gmail.com | ff6sadfa4325342235233243dsffds |\n| example@gmail.com | gandjubasik_91 |\n| example@gmail.com | kaylateam23 |\n| example@gmail.com | andreev |\n| example@gmail.com | 1234560 |\n| example@gmail.com | 15108302012 |\n| example@gmail.com | 593555 |\n| example@gmail.com | 12345 |\n| example@gmail.com | gandjubasik_91 |\n| example@gmail.com | asdfghjk |\n| example@gmail.com | 89506752655 |\n| example@gmail.com | bagrat |\n| example@gmail.com | December |\n| example@gmail.com | Squid |\n| example@gmail.com | ekawebop |\n| example@gmail.com | lol |\n| example@gmail.com | stormy |\n| example@gmail.com | Example213 |\n| example@gmail.com | 123123123 |\n| Example@gmail.com | 1234567 |\n| example@gmail.com | Connor12 |\n| example@gmail.com | hi |\n| example@gmail.com | 08amy |\n| example@gmail.com | mastergamer12 |\n| example@gmail.com | 1234567890 |\n| example@gmail.com | 01012243 |\n| example@gmail.com | loulou17 |\n| example@gmail.com | hiseth |\n| example@gmail.com | elementqaz |\n| example@gmail.com | Volution |\n| example@gmail.com | 45165153 |\n| example@gmail.com | 2346689512513 |\n| example@gmail.com | fcea920f7412b5da7be0cf42b8c93759 |\n| example@gmail.com | hiltonlover77 |\n| example@gmail.com | aak2002dn |\n| example@gmail.com | 1234567 |\n| example@gmail.com | westpark1 |\n| example@gmail.com | 123456 |\n| example@gmail.com | pic |\n| example@gmail.com | example@gmail.com |\n| example@gmail.com | scorpian7887 |\n| example@gmail.com | 89506752655 |\n| example@gmail.com | brantford1 |\n+-------------------+----------------------------------+\n', 'Karma find leaked emails with your passwords. If you have located a known password linked to your email, you MUST change it immediately.\r\n\r\nFIX THIS \r\nIt is recommended to change the password of your email and all the services you use (Facebook, Twitter, Snapchat, Instagram, Netflix, Spotify, etc). To do so, go to the official website or service app and change your password in SETTINGS.
\r\n\r\nCreate a strong password that is totally different from the current one and avoid using personal data such as date of birth, name, cpf, etc. Combining letters, numbers and special characters will only increase your security.
\r\n\r\nPROTECTION \r\nTo increase your security, it is recommended that you enable two-factor authentication .
', '2019-07-05 09:09:55');
-- --------------------------------------------------------
--
-- Estrutura da tabela `tools`
--
CREATE TABLE `tools` (
`id` int(11) NOT NULL,
`name` varchar(100) DEFAULT NULL,
`fullname` varchar(150) DEFAULT NULL,
`categories` varchar(300) DEFAULT NULL,
`description` varchar(500) DEFAULT NULL,
`site` varchar(100) DEFAULT NULL,
`github` varchar(500) DEFAULT NULL,
`released` tinytext DEFAULT NULL,
`avatar` varchar(100) DEFAULT NULL,
`cmd` varchar(100) DEFAULT NULL,
`target` varchar(10) DEFAULT NULL,
`resume` text DEFAULT NULL,
`category` varchar(100) DEFAULT NULL,
`category2` varchar(100) DEFAULT NULL,
`solution` text DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Extraindo dados da tabela `tools`
--
INSERT INTO `tools` (`id`, `name`, `fullname`, `categories`, `description`, `site`, `github`, `released`, `avatar`, `cmd`, `target`, `resume`, `category`, `category2`, `solution`) VALUES
(1, 'Nmap', 'Nmap: the Network Mapper', 'information-gathering vulnerability -analysis', 'https://tools.kali.org/information-gathering/nmap', 'https://insecure.org/', NULL, 'Yes', 'assets/img/nmap.jpg', 'nmap', NULL, 'Nmap (“Network Mapper”) is a free and open source (license) utility for network discovery and security auditing. Many systems and network administrators also find it useful for tasks such as network inventory, managing service upgrade schedules, and monitoring host or service uptime.', 'Information Gathering', 'Vulnerability Analysis', 'Nmap works by checking a network for hosts and services. Once found, the software platform sends information to those hosts and services which then respond.\r\n\r\nFIX THIS \r\n
\r\n\r\n\r\nPROTECTION \r\n
'),
(2, 'BetterCap', 'bettercap', 'sniffing-spoofing', 'https://tools.kali.org/sniffingspoofing/bettercap', 'https://www.bettercap.org/', NULL, NULL, 'assets/img/bettercap.jpg', 'bettercap', NULL, NULL, 'Sniffing & Spoofing', NULL, NULL),
(3, 'theHarvester', 'theHarvester', 'information-gathering ', 'https://tools.kali.org/information-gathering/theharvester', NULL, 'https://github.com/laramies/theHarvester', 'Yes', NULL, 'python /home/kali/Downloads/theHarvester/theHarvester.py', '-d', 'The objective of this program is to gather emails, subdomains, hosts, employee names, open ports and banners from different public sources like search engines, PGP key servers and SHODAN computer database.', 'Information Gathering', NULL, 'theHarvester is a great tool for collecting information from a particular host, with it it is possible to get a list of emails, subdomains, hosts, employee names, open ports, banners from different public sources, PGP keys and mapped information by SHODAN.\r\n\r\nFIX THIS \r\n\r\nThe information found by theHarvester is indexed in Internet pages. If you want to hide this content you need to identify in the source of this information.\r\nFor this, one can be applied techniques like Google Hacking to refine the search in search engines users by theHarvester.\r\n\r\nOnce the data source is identified, you can hide or delete the data, for example, from a social network. If it is a content of your own, such as a personal blog, just create a robots.txt file and hide the pages that have the information.\r\n
\r\n\r\n\r\nUSEFUL LINKS \r\n\r\n • Google Hacking Techniques \r\n • Best Practices robots.txt \r\n\r\n '),
(4, 'Nikto', 'Nikto', 'information-gathering web-applications', 'https://tools.kali.org/information-gathering/nikto', 'https://www.cirt.net/Nikto2', 'https://github.com/sullo/nikto', NULL, 'assets/img/nikto.png', 'nikto', '-h', NULL, 'Information Gathering', 'Web Applications', NULL),
(5, 'Aircrack-ng', 'Airckack-ng', 'wireless- attacks', 'https://tools.kali.org/wireless-attacks/aircrack-ng', 'https://www.aircrack-ng.org/doku.php?id=aircrack-ng', 'https://gitlab.com/kalilinux/packages/aircrack-ng', NULL, NULL, NULL, NULL, NULL, 'Wireless Attacks', NULL, NULL),
(6, 'THC-Hydra', 'THC-Hydra', 'password-attacks', 'https://tools.kali.org/password-attacks/hydra', 'http://freeworld.thc.org/thc-hydra/', NULL, NULL, 'assets/img/hydrathc.jpg', NULL, NULL, NULL, 'Password Attacks', NULL, NULL),
(7, 'WPScan', 'WordPress Vulnerability Scanner', 'web-applications', 'https://tools.kali.org/web-applications/wpscan', 'http://wpscan.org/', 'https://github.com/wpscanteam/wpscan', NULL, 'assets/img/wpscan.png', 'wpscan', '--url', 'WPScan is a black box WordPress vulnerability scanner that can be used to scan remote WordPress installations to find security issues.', 'Web Applications', NULL, NULL),
(8, 'Dnstracer', 'dnstracer', 'information-gathering', 'https://tools.kali.org/information-gathering/dnstracer', 'http://freshmeat.net/projects/dnstracer', NULL, 'Yes', NULL, 'dnstracer', NULL, 'dnstracer determines where a given Domain Name Server (DNS) gets its information from for a given hostname, and follows the chain of DNS servers back to the authoritative answer.', 'Information Gathering', NULL, NULL),
(10, 'Sqlninja', 'Sqlninja', 'vulnerability-analysis web-applications', 'https://tools.kali.org/vulnerability-analysis/sqlninja', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Vulnerability Analysis', 'Web Applications', NULL),
(11, 'Powerfuzzer', 'Powerfuzzer', 'vulnerability-analysis web-applications', 'https://tools.kali.org/vulnerability-analysis/powerfuzzer', 'https://www.powerfuzzer.com/', NULL, NULL, NULL, NULL, NULL, NULL, 'Vulnerability Analysis', 'Web Applications', NULL),
(12, 'ProxyStrike', 'ProxyStrike', 'web-applications', 'https://tools.kali.org/web-applications/proxystrike', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Web Applications', NULL, NULL),
(14, 'Dnsenum', 'Dnsenum', 'information-gathering', 'https://tools.kali.org/information-gathering/dnsenum', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'Information Gathering', NULL, NULL),
(15, 'Karma', 'Karma', 'information-gathering', NULL, NULL, 'https://github.com/decoxviii/karma', 'Yes', 'assets/img/github.jpg', 'karma', 'target', 'Find leaked emails with your passwords.', 'Information Gathering', NULL, 'Karma find leaked emails with your passwords. If you have located a known password linked to your email, you MUST change it immediately.\r\n\r\nFIX THIS \r\nIt is recommended to change the password of your email and all the services you use (Facebook, Twitter, Snapchat, Instagram, Netflix, Spotify, etc). To do so, go to the official website or service app and change your password in SETTINGS.
\r\n\r\nCreate a strong password that is totally different from the current one and avoid using personal data such as date of birth, name, cpf, etc. Combining letters, numbers and special characters will only increase your security.
\r\n\r\nPROTECTION \r\nTo increase your security, it is recommended that you enable two-factor authentication .
');
--
-- Índices para tabelas despejadas
--
--
-- Índices para tabela `commands`
--
ALTER TABLE `commands`
ADD PRIMARY KEY (`id`);
--
-- Índices para tabela `reports`
--
ALTER TABLE `reports`
ADD PRIMARY KEY (`id`);
--
-- Índices para tabela `tools`
--
ALTER TABLE `tools`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT de tabelas despejadas
--
--
-- AUTO_INCREMENT de tabela `commands`
--
ALTER TABLE `commands`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=97;
--
-- AUTO_INCREMENT de tabela `reports`
--
ALTER TABLE `reports`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=63;
--
-- AUTO_INCREMENT de tabela `tools`
--
ALTER TABLE `tools`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=16;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
================================================
FILE: assets/includes/config.php
================================================
"SET NAMES 'utf8'"));
return $con;
}
session_start();
// Verifica se existe os dados da sessão de login
if (!isset($_SESSION["host"]) || !isset($_SESSION["user"]) || !isset($_SESSION["password"])) {
header("Location: login.php");
} else {
$name = $_SESSION["user"];
$avatar = "assets/img/profile.jpg";
$background = "assets/img/background.jpg";
}
?>
================================================
FILE: assets/includes/footer.php
================================================
================================================
FILE: assets/includes/head.php
================================================
Kali Linux Tools Interface
================================================
FILE: assets/includes/header.php
================================================
================================================
FILE: assets/includes/list-commands.php
================================================
List of commands
Command
prepare("SELECT command, name, examples, type FROM commands WHERE tool=$tool ORDER BY name");
$sql2->execute();
$resultados2 = $sql2->fetchAll(PDO::FETCH_ASSOC);
// FOREACH BEGINS
foreach ($resultados2 as $resultado2) {
$command = $resultado2['command'];
$name = $resultado2['name'];
$examples = $resultado2['examples'];
$type = $resultado2['type'];
echo
"
$name ";
if ($type == "input") {
echo " Input Text ";
} else if ($type == "checkbox") {
echo " Checkbox ";
} else if ($type == "target") {
echo " Target ";
} else if ($type == "show") {
echo " Show Info ";
}
echo
" $command
";
}
?>
================================================
FILE: assets/includes/tools-categories.php
================================================
All
Information Gathering
Password Attacks
Sniffing & Spoofing
Vulnerability Analysis
Web Applications
================================================
FILE: assets/js/argon.js
================================================
/*!
=========================================================
* Argon Dashboard - v1.0.0
=========================================================
* Product Page: https://www.creative-tim.com/product/argon-dashboard
* Copyright 2018 Creative Tim (https://www.creative-tim.com)
* Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard/blob/master/LICENSE.md)
* Coded by www.creative-tim.com
=========================================================
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
//
// Bootstrap Datepicker
//
'use strict';
var Datepicker = (function() {
// Variables
var $datepicker = $('.datepicker');
// Methods
function init($this) {
var options = {
disableTouchKeyboard: true,
autoclose: false
};
$this.datepicker(options);
}
// Events
if ($datepicker.length) {
$datepicker.each(function() {
init($(this));
});
}
})();
//
// Icon code copy/paste
//
'use strict';
var CopyIcon = (function() {
// Variables
var $element = '.btn-icon-clipboard',
$btn = $($element);
// Methods
function init($this) {
$this.tooltip().on('mouseleave', function() {
// Explicitly hide tooltip, since after clicking it remains
// focused (as it's a button), so tooltip would otherwise
// remain visible until focus is moved away
$this.tooltip('hide');
});
var clipboard = new ClipboardJS($element);
clipboard.on('success', function(e) {
$(e.trigger)
.attr('title', 'Copied!')
.tooltip('_fixTitle')
.tooltip('show')
.attr('title', 'Copy to clipboard')
.tooltip('_fixTitle')
e.clearSelection()
});
}
// Events
if ($btn.length) {
init($btn);
}
})();
//
// Form control
//
'use strict';
var FormControl = (function() {
// Variables
var $input = $('.form-control');
// Methods
function init($this) {
$this.on('focus blur', function(e) {
$(this).parents('.form-group').toggleClass('focused', (e.type === 'focus' || this.value.length > 0));
}).trigger('blur');
}
// Events
if ($input.length) {
init($input);
}
})();
//
// Google maps
//
var $map = $('#map-canvas'),
map,
lat,
lng,
color = "#5e72e4";
function initMap() {
map = document.getElementById('map-canvas');
lat = map.getAttribute('data-lat');
lng = map.getAttribute('data-lng');
var myLatlng = new google.maps.LatLng(lat, lng);
var mapOptions = {
zoom: 12,
scrollwheel: false,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
styles: [{"featureType":"administrative","elementType":"labels.text.fill","stylers":[{"color":"#444444"}]},{"featureType":"landscape","elementType":"all","stylers":[{"color":"#f2f2f2"}]},{"featureType":"poi","elementType":"all","stylers":[{"visibility":"off"}]},{"featureType":"road","elementType":"all","stylers":[{"saturation":-100},{"lightness":45}]},{"featureType":"road.highway","elementType":"all","stylers":[{"visibility":"simplified"}]},{"featureType":"road.arterial","elementType":"labels.icon","stylers":[{"visibility":"off"}]},{"featureType":"transit","elementType":"all","stylers":[{"visibility":"off"}]},{"featureType":"water","elementType":"all","stylers":[{"color":color},{"visibility":"on"}]}]
}
map = new google.maps.Map(map, mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
animation: google.maps.Animation.DROP,
title: 'Hello World!'
});
var contentString = '
Argon Dashboard ' +
'
A beautiful Dashboard for Bootstrap 4. It is Free and Open Source.
';
var infowindow = new google.maps.InfoWindow({
content: contentString
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map, marker);
});
}
if($map.length) {
google.maps.event.addDomListener(window, 'load', initMap);
}
// //
// // Headroom - show/hide navbar on scroll
// //
//
// 'use strict';
//
// var Headroom = (function() {
//
// // Variables
//
// var $headroom = $('#navbar-main');
//
//
// // Methods
//
// function init($this) {
//
// var headroom = new Headroom(document.querySelector("#navbar-main"), {
// offset: 300,
// tolerance: {
// up: 30,
// down: 30
// },
// });
//
//
//
// // Events
//
// if ($headroom.length) {
// headroom.init();
// }
//
// })();
//
// Navbar
//
'use strict';
var Navbar = (function() {
// Variables
var $nav = $('.navbar-nav, .navbar-nav .nav');
var $collapse = $('.navbar .collapse');
var $dropdown = $('.navbar .dropdown');
// Methods
function accordion($this) {
$this.closest($nav).find($collapse).not($this).collapse('hide');
}
function closeDropdown($this) {
var $dropdownMenu = $this.find('.dropdown-menu');
$dropdownMenu.addClass('close');
setTimeout(function() {
$dropdownMenu.removeClass('close');
}, 200);
}
// Events
$collapse.on({
'show.bs.collapse': function() {
accordion($(this));
}
})
$dropdown.on({
'hide.bs.dropdown': function() {
closeDropdown($(this));
}
})
})();
//
// Navbar collapse
//
var NavbarCollapse = (function() {
// Variables
var $nav = $('.navbar-nav'),
$collapse = $('.navbar .collapse');
// Methods
function hideNavbarCollapse($this) {
$this.addClass('collapsing-out');
}
function hiddenNavbarCollapse($this) {
$this.removeClass('collapsing-out');
}
// Events
if ($collapse.length) {
$collapse.on({
'hide.bs.collapse': function() {
hideNavbarCollapse($collapse);
}
})
$collapse.on({
'hidden.bs.collapse': function() {
hiddenNavbarCollapse($collapse);
}
})
}
})();
//
// Form control
//
'use strict';
var noUiSlider = (function() {
// Variables
// var $sliderContainer = $('.input-slider-container'),
// $slider = $('.input-slider'),
// $sliderId = $slider.attr('id'),
// $sliderMinValue = $slider.data('range-value-min');
// $sliderMaxValue = $slider.data('range-value-max');;
// // Methods
//
// function init($this) {
// $this.on('focus blur', function(e) {
// $this.parents('.form-group').toggleClass('focused', (e.type === 'focus' || this.value.length > 0));
// }).trigger('blur');
// }
//
//
// // Events
//
// if ($input.length) {
// init($input);
// }
if ($(".input-slider-container")[0]) {
$('.input-slider-container').each(function() {
var slider = $(this).find('.input-slider');
var sliderId = slider.attr('id');
var minValue = slider.data('range-value-min');
var maxValue = slider.data('range-value-max');
var sliderValue = $(this).find('.range-slider-value');
var sliderValueId = sliderValue.attr('id');
var startValue = sliderValue.data('range-value-low');
var c = document.getElementById(sliderId),
d = document.getElementById(sliderValueId);
noUiSlider.create(c, {
start: [parseInt(startValue)],
connect: [true, false],
//step: 1000,
range: {
'min': [parseInt(minValue)],
'max': [parseInt(maxValue)]
}
});
c.noUiSlider.on('update', function(a, b) {
d.textContent = a[b];
});
})
}
if ($("#input-slider-range")[0]) {
var c = document.getElementById("input-slider-range"),
d = document.getElementById("input-slider-range-value-low"),
e = document.getElementById("input-slider-range-value-high"),
f = [d, e];
noUiSlider.create(c, {
start: [parseInt(d.getAttribute('data-range-value-low')), parseInt(e.getAttribute('data-range-value-high'))],
connect: !0,
range: {
min: parseInt(c.getAttribute('data-range-value-min')),
max: parseInt(c.getAttribute('data-range-value-max'))
}
}), c.noUiSlider.on("update", function(a, b) {
f[b].textContent = a[b]
})
}
})();
//
// Popover
//
'use strict';
var Popover = (function() {
// Variables
var $popover = $('[data-toggle="popover"]'),
$popoverClass = '';
// Methods
function init($this) {
if ($this.data('color')) {
$popoverClass = 'popover-' + $this.data('color');
}
var options = {
trigger: 'focus',
template: '
'
};
$this.popover(options);
}
// Events
if ($popover.length) {
$popover.each(function() {
init($(this));
});
}
})();
//
// Scroll to (anchor links)
//
'use strict';
var ScrollTo = (function() {
//
// Variables
//
var $scrollTo = $('.scroll-me, [data-scroll-to], .toc-entry a');
//
// Methods
//
function scrollTo($this) {
var $el = $this.attr('href');
var offset = $this.data('scroll-to-offset') ? $this.data('scroll-to-offset') : 0;
var options = {
scrollTop: $($el).offset().top - offset
};
// Animate scroll to the selected section
$('html, body').stop(true, true).animate(options, 600);
event.preventDefault();
}
//
// Events
//
if ($scrollTo.length) {
$scrollTo.on('click', function(event) {
scrollTo($(this));
});
}
})();
//
// Tooltip
//
'use strict';
var Tooltip = (function() {
// Variables
var $tooltip = $('[data-toggle="tooltip"]');
// Methods
function init() {
$tooltip.tooltip();
}
// Events
if ($tooltip.length) {
init();
}
})();
//
// Charts
//
'use strict';
var Charts = (function() {
// Variable
var $toggle = $('[data-toggle="chart"]');
var mode = 'light';//(themeMode) ? themeMode : 'light';
var fonts = {
base: 'Open Sans'
}
// Colors
var colors = {
gray: {
100: '#f6f9fc',
200: '#e9ecef',
300: '#dee2e6',
400: '#ced4da',
500: '#adb5bd',
600: '#8898aa',
700: '#525f7f',
800: '#32325d',
900: '#212529'
},
theme: {
'default': '#172b4d',
'primary': '#5e72e4',
'secondary': '#f4f5f7',
'info': '#11cdef',
'success': '#2dce89',
'danger': '#f5365c',
'warning': '#fb6340'
},
black: '#12263F',
white: '#FFFFFF',
transparent: 'transparent',
};
// Methods
// Chart.js global options
function chartOptions() {
// Options
var options = {
defaults: {
global: {
responsive: true,
maintainAspectRatio: false,
defaultColor: (mode == 'dark') ? colors.gray[700] : colors.gray[600],
defaultFontColor: (mode == 'dark') ? colors.gray[700] : colors.gray[600],
defaultFontFamily: fonts.base,
defaultFontSize: 13,
layout: {
padding: 0
},
legend: {
display: false,
position: 'bottom',
labels: {
usePointStyle: true,
padding: 16
}
},
elements: {
point: {
radius: 0,
backgroundColor: colors.theme['primary']
},
line: {
tension: .4,
borderWidth: 4,
borderColor: colors.theme['primary'],
backgroundColor: colors.transparent,
borderCapStyle: 'rounded'
},
rectangle: {
backgroundColor: colors.theme['warning']
},
arc: {
backgroundColor: colors.theme['primary'],
borderColor: (mode == 'dark') ? colors.gray[800] : colors.white,
borderWidth: 4
}
},
tooltips: {
enabled: false,
mode: 'index',
intersect: false,
custom: function(model) {
// Get tooltip
var $tooltip = $('#chart-tooltip');
// Create tooltip on first render
if (!$tooltip.length) {
$tooltip = $('
');
// Append to body
$('body').append($tooltip);
}
// Hide if no tooltip
if (model.opacity === 0) {
$tooltip.css('display', 'none');
return;
}
function getBody(bodyItem) {
return bodyItem.lines;
}
// Fill with content
if (model.body) {
var titleLines = model.title || [];
var bodyLines = model.body.map(getBody);
var html = '';
// Add arrow
html += '
';
// Add header
titleLines.forEach(function(title) {
html += '';
});
// Add body
bodyLines.forEach(function(body, i) {
var colors = model.labelColors[i];
var styles = 'background-color: ' + colors.backgroundColor;
var indicator = '
';
var align = (bodyLines.length > 1) ? 'justify-content-left' : 'justify-content-center';
html += '
' + indicator + body + '
';
});
$tooltip.html(html);
}
// Get tooltip position
var $canvas = $(this._chart.canvas);
var canvasWidth = $canvas.outerWidth();
var canvasHeight = $canvas.outerHeight();
var canvasTop = $canvas.offset().top;
var canvasLeft = $canvas.offset().left;
var tooltipWidth = $tooltip.outerWidth();
var tooltipHeight = $tooltip.outerHeight();
var top = canvasTop + model.caretY - tooltipHeight - 16;
var left = canvasLeft + model.caretX - tooltipWidth / 2;
// Display tooltip
$tooltip.css({
'top': top + 'px',
'left': left + 'px',
'display': 'block',
'z-index': '100'
});
},
callbacks: {
label: function(item, data) {
var label = data.datasets[item.datasetIndex].label || '';
var yLabel = item.yLabel;
var content = '';
if (data.datasets.length > 1) {
content += '
' + label + ' ';
}
content += '
' + yLabel + ' ' ;
return content;
}
}
}
},
doughnut: {
cutoutPercentage: 83,
tooltips: {
callbacks: {
title: function(item, data) {
var title = data.labels[item[0].index];
return title;
},
label: function(item, data) {
var value = data.datasets[0].data[item.index];
var content = '';
content += '
' + value + ' ';
return content;
}
}
},
legendCallback: function(chart) {
var data = chart.data;
var content = '';
data.labels.forEach(function(label, index) {
var bgColor = data.datasets[0].backgroundColor[index];
content += '
';
content += ' ';
content += label;
content += ' ';
});
return content;
}
}
}
}
// yAxes
Chart.scaleService.updateScaleDefaults('linear', {
gridLines: {
borderDash: [2],
borderDashOffset: [2],
color: (mode == 'dark') ? colors.gray[900] : colors.gray[300],
drawBorder: false,
drawTicks: false,
lineWidth: 0,
zeroLineWidth: 0,
zeroLineColor: (mode == 'dark') ? colors.gray[900] : colors.gray[300],
zeroLineBorderDash: [2],
zeroLineBorderDashOffset: [2]
},
ticks: {
beginAtZero: true,
padding: 10,
callback: function(value) {
if (!(value % 10)) {
return value
}
}
}
});
// xAxes
Chart.scaleService.updateScaleDefaults('category', {
gridLines: {
drawBorder: false,
drawOnChartArea: false,
drawTicks: false
},
ticks: {
padding: 20
},
maxBarThickness: 10
});
return options;
}
// Parse global options
function parseOptions(parent, options) {
for (var item in options) {
if (typeof options[item] !== 'object') {
parent[item] = options[item];
} else {
parseOptions(parent[item], options[item]);
}
}
}
// Push options
function pushOptions(parent, options) {
for (var item in options) {
if (Array.isArray(options[item])) {
options[item].forEach(function(data) {
parent[item].push(data);
});
} else {
pushOptions(parent[item], options[item]);
}
}
}
// Pop options
function popOptions(parent, options) {
for (var item in options) {
if (Array.isArray(options[item])) {
options[item].forEach(function(data) {
parent[item].pop();
});
} else {
popOptions(parent[item], options[item]);
}
}
}
// Toggle options
function toggleOptions(elem) {
var options = elem.data('add');
var $target = $(elem.data('target'));
var $chart = $target.data('chart');
if (elem.is(':checked')) {
// Add options
pushOptions($chart, options);
// Update chart
$chart.update();
} else {
// Remove options
popOptions($chart, options);
// Update chart
$chart.update();
}
}
// Update options
function updateOptions(elem) {
var options = elem.data('update');
var $target = $(elem.data('target'));
var $chart = $target.data('chart');
// Parse options
parseOptions($chart, options);
// Toggle ticks
toggleTicks(elem, $chart);
// Update chart
$chart.update();
}
// Toggle ticks
function toggleTicks(elem, $chart) {
if (elem.data('prefix') !== undefined || elem.data('prefix') !== undefined) {
var prefix = elem.data('prefix') ? elem.data('prefix') : '';
var suffix = elem.data('suffix') ? elem.data('suffix') : '';
// Update ticks
$chart.options.scales.yAxes[0].ticks.callback = function(value) {
if (!(value % 10)) {
return prefix + value + suffix;
}
}
// Update tooltips
$chart.options.tooltips.callbacks.label = function(item, data) {
var label = data.datasets[item.datasetIndex].label || '';
var yLabel = item.yLabel;
var content = '';
if (data.datasets.length > 1) {
content += '
' + label + ' ';
}
content += '
' + prefix + yLabel + suffix + ' ';
return content;
}
}
}
// Events
// Parse global options
if (window.Chart) {
parseOptions(Chart, chartOptions());
}
// Toggle options
$toggle.on({
'change': function() {
var $this = $(this);
if ($this.is('[data-add]')) {
toggleOptions($this);
}
},
'click': function() {
var $this = $(this);
if ($this.is('[data-update]')) {
updateOptions($this);
}
}
});
// Return
return {
colors: colors,
fonts: fonts,
mode: mode
};
})();
//
// Orders chart
//
var OrdersChart = (function() {
//
// Variables
//
var $chart = $('#chart-orders');
var $ordersSelect = $('[name="ordersSelect"]');
//
// Methods
//
// Init chart
function initChart($chart) {
// Create chart
var ordersChart = new Chart($chart, {
type: 'bar',
options: {
scales: {
yAxes: [{
ticks: {
callback: function(value) {
if (!(value % 10)) {
//return '$' + value + 'k'
return value
}
}
}
}]
},
tooltips: {
callbacks: {
label: function(item, data) {
var label = data.datasets[item.datasetIndex].label || '';
var yLabel = item.yLabel;
var content = '';
if (data.datasets.length > 1) {
content += '
' + label + ' ';
}
content += '
' + yLabel + ' ';
return content;
}
}
}
},
data: {
labels: ['Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
datasets: [{
label: 'Sales',
data: [25, 20, 30, 22, 17, 29]
}]
}
});
// Save to jQuery object
$chart.data('chart', ordersChart);
}
// Init chart
if ($chart.length) {
initChart($chart);
}
})();
//
// Charts
//
'use strict';
//
// Sales chart
//
var SalesChart = (function() {
// Variables
var $chart = $('#chart-sales');
// Methods
function init($chart) {
var salesChart = new Chart($chart, {
type: 'line',
options: {
scales: {
yAxes: [{
gridLines: {
color: Charts.colors.gray[900],
zeroLineColor: Charts.colors.gray[900]
},
ticks: {
callback: function(value) {
if (!(value % 10)) {
return '$' + value + 'k';
}
}
}
}]
},
tooltips: {
callbacks: {
label: function(item, data) {
var label = data.datasets[item.datasetIndex].label || '';
var yLabel = item.yLabel;
var content = '';
if (data.datasets.length > 1) {
content += '
' + label + ' ';
}
content += '
$' + yLabel + 'k ';
return content;
}
}
}
},
data: {
labels: ['May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
datasets: [{
label: 'Performance',
data: [0, 20, 10, 30, 15, 40, 20, 60, 60]
}]
}
});
// Save to jQuery object
$chart.data('chart', salesChart);
};
// Events
if ($chart.length) {
init($chart);
}
})();
================================================
FILE: assets/js/bootstrap.js
================================================
/*!
* Bootstrap v4.0.0 (https://getbootstrap.com)
* Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery'), require('popper.js')) :
typeof define === 'function' && define.amd ? define(['exports', 'jquery', 'popper.js'], factory) :
(factory((global.bootstrap = {}),global.jQuery,global.Popper));
}(this, (function (exports,$,Popper) { 'use strict';
$ = $ && $.hasOwnProperty('default') ? $['default'] : $;
Popper = Popper && Popper.hasOwnProperty('default') ? Popper['default'] : Popper;
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
subClass.__proto__ = superClass;
}
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0): util.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var Util = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Private TransitionEnd Helpers
* ------------------------------------------------------------------------
*/
var transition = false;
var MAX_UID = 1000000; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
function toType(obj) {
return {}.toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}
function getSpecialTransitionEndEvent() {
return {
bindType: transition.end,
delegateType: transition.end,
handle: function handle(event) {
if ($$$1(event.target).is(this)) {
return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params
}
return undefined; // eslint-disable-line no-undefined
}
};
}
function transitionEndTest() {
if (typeof window !== 'undefined' && window.QUnit) {
return false;
}
return {
end: 'transitionend'
};
}
function transitionEndEmulator(duration) {
var _this = this;
var called = false;
$$$1(this).one(Util.TRANSITION_END, function () {
called = true;
});
setTimeout(function () {
if (!called) {
Util.triggerTransitionEnd(_this);
}
}, duration);
return this;
}
function setTransitionEndSupport() {
transition = transitionEndTest();
$$$1.fn.emulateTransitionEnd = transitionEndEmulator;
if (Util.supportsTransitionEnd()) {
$$$1.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();
}
}
function escapeId(selector) {
// We escape IDs in case of special selectors (selector = '#myId:something')
// $.escapeSelector does not exist in jQuery < 3
selector = typeof $$$1.escapeSelector === 'function' ? $$$1.escapeSelector(selector).substr(1) : selector.replace(/(:|\.|\[|\]|,|=|@)/g, '\\$1');
return selector;
}
/**
* --------------------------------------------------------------------------
* Public Util Api
* --------------------------------------------------------------------------
*/
var Util = {
TRANSITION_END: 'bsTransitionEnd',
getUID: function getUID(prefix) {
do {
// eslint-disable-next-line no-bitwise
prefix += ~~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here
} while (document.getElementById(prefix));
return prefix;
},
getSelectorFromElement: function getSelectorFromElement(element) {
var selector = element.getAttribute('data-target');
if (!selector || selector === '#') {
selector = element.getAttribute('href') || '';
} // If it's an ID
if (selector.charAt(0) === '#') {
selector = escapeId(selector);
}
try {
var $selector = $$$1(document).find(selector);
return $selector.length > 0 ? selector : null;
} catch (err) {
return null;
}
},
reflow: function reflow(element) {
return element.offsetHeight;
},
triggerTransitionEnd: function triggerTransitionEnd(element) {
$$$1(element).trigger(transition.end);
},
supportsTransitionEnd: function supportsTransitionEnd() {
return Boolean(transition);
},
isElement: function isElement(obj) {
return (obj[0] || obj).nodeType;
},
typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {
for (var property in configTypes) {
if (Object.prototype.hasOwnProperty.call(configTypes, property)) {
var expectedTypes = configTypes[property];
var value = config[property];
var valueType = value && Util.isElement(value) ? 'element' : toType(value);
if (!new RegExp(expectedTypes).test(valueType)) {
throw new Error(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\"."));
}
}
}
}
};
setTransitionEndSupport();
return Util;
}($);
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0): alert.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var Alert = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'alert';
var VERSION = '4.0.0';
var DATA_KEY = 'bs.alert';
var EVENT_KEY = "." + DATA_KEY;
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var TRANSITION_DURATION = 150;
var Selector = {
DISMISS: '[data-dismiss="alert"]'
};
var Event = {
CLOSE: "close" + EVENT_KEY,
CLOSED: "closed" + EVENT_KEY,
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
};
var ClassName = {
ALERT: 'alert',
FADE: 'fade',
SHOW: 'show'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var Alert =
/*#__PURE__*/
function () {
function Alert(element) {
this._element = element;
} // Getters
var _proto = Alert.prototype;
// Public
_proto.close = function close(element) {
element = element || this._element;
var rootElement = this._getRootElement(element);
var customEvent = this._triggerCloseEvent(rootElement);
if (customEvent.isDefaultPrevented()) {
return;
}
this._removeElement(rootElement);
};
_proto.dispose = function dispose() {
$$$1.removeData(this._element, DATA_KEY);
this._element = null;
}; // Private
_proto._getRootElement = function _getRootElement(element) {
var selector = Util.getSelectorFromElement(element);
var parent = false;
if (selector) {
parent = $$$1(selector)[0];
}
if (!parent) {
parent = $$$1(element).closest("." + ClassName.ALERT)[0];
}
return parent;
};
_proto._triggerCloseEvent = function _triggerCloseEvent(element) {
var closeEvent = $$$1.Event(Event.CLOSE);
$$$1(element).trigger(closeEvent);
return closeEvent;
};
_proto._removeElement = function _removeElement(element) {
var _this = this;
$$$1(element).removeClass(ClassName.SHOW);
if (!Util.supportsTransitionEnd() || !$$$1(element).hasClass(ClassName.FADE)) {
this._destroyElement(element);
return;
}
$$$1(element).one(Util.TRANSITION_END, function (event) {
return _this._destroyElement(element, event);
}).emulateTransitionEnd(TRANSITION_DURATION);
};
_proto._destroyElement = function _destroyElement(element) {
$$$1(element).detach().trigger(Event.CLOSED).remove();
}; // Static
Alert._jQueryInterface = function _jQueryInterface(config) {
return this.each(function () {
var $element = $$$1(this);
var data = $element.data(DATA_KEY);
if (!data) {
data = new Alert(this);
$element.data(DATA_KEY, data);
}
if (config === 'close') {
data[config](this);
}
});
};
Alert._handleDismiss = function _handleDismiss(alertInstance) {
return function (event) {
if (event) {
event.preventDefault();
}
alertInstance.close(this);
};
};
_createClass(Alert, null, [{
key: "VERSION",
get: function get() {
return VERSION;
}
}]);
return Alert;
}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
$$$1(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = Alert._jQueryInterface;
$$$1.fn[NAME].Constructor = Alert;
$$$1.fn[NAME].noConflict = function () {
$$$1.fn[NAME] = JQUERY_NO_CONFLICT;
return Alert._jQueryInterface;
};
return Alert;
}($);
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0): button.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var Button = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'button';
var VERSION = '4.0.0';
var DATA_KEY = 'bs.button';
var EVENT_KEY = "." + DATA_KEY;
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var ClassName = {
ACTIVE: 'active',
BUTTON: 'btn',
FOCUS: 'focus'
};
var Selector = {
DATA_TOGGLE_CARROT: '[data-toggle^="button"]',
DATA_TOGGLE: '[data-toggle="buttons"]',
INPUT: 'input',
ACTIVE: '.active',
BUTTON: '.btn'
};
var Event = {
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY,
FOCUS_BLUR_DATA_API: "focus" + EVENT_KEY + DATA_API_KEY + " " + ("blur" + EVENT_KEY + DATA_API_KEY)
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var Button =
/*#__PURE__*/
function () {
function Button(element) {
this._element = element;
} // Getters
var _proto = Button.prototype;
// Public
_proto.toggle = function toggle() {
var triggerChangeEvent = true;
var addAriaPressed = true;
var rootElement = $$$1(this._element).closest(Selector.DATA_TOGGLE)[0];
if (rootElement) {
var input = $$$1(this._element).find(Selector.INPUT)[0];
if (input) {
if (input.type === 'radio') {
if (input.checked && $$$1(this._element).hasClass(ClassName.ACTIVE)) {
triggerChangeEvent = false;
} else {
var activeElement = $$$1(rootElement).find(Selector.ACTIVE)[0];
if (activeElement) {
$$$1(activeElement).removeClass(ClassName.ACTIVE);
}
}
}
if (triggerChangeEvent) {
if (input.hasAttribute('disabled') || rootElement.hasAttribute('disabled') || input.classList.contains('disabled') || rootElement.classList.contains('disabled')) {
return;
}
input.checked = !$$$1(this._element).hasClass(ClassName.ACTIVE);
$$$1(input).trigger('change');
}
input.focus();
addAriaPressed = false;
}
}
if (addAriaPressed) {
this._element.setAttribute('aria-pressed', !$$$1(this._element).hasClass(ClassName.ACTIVE));
}
if (triggerChangeEvent) {
$$$1(this._element).toggleClass(ClassName.ACTIVE);
}
};
_proto.dispose = function dispose() {
$$$1.removeData(this._element, DATA_KEY);
this._element = null;
}; // Static
Button._jQueryInterface = function _jQueryInterface(config) {
return this.each(function () {
var data = $$$1(this).data(DATA_KEY);
if (!data) {
data = new Button(this);
$$$1(this).data(DATA_KEY, data);
}
if (config === 'toggle') {
data[config]();
}
});
};
_createClass(Button, null, [{
key: "VERSION",
get: function get() {
return VERSION;
}
}]);
return Button;
}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
$$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) {
event.preventDefault();
var button = event.target;
if (!$$$1(button).hasClass(ClassName.BUTTON)) {
button = $$$1(button).closest(Selector.BUTTON);
}
Button._jQueryInterface.call($$$1(button), 'toggle');
}).on(Event.FOCUS_BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) {
var button = $$$1(event.target).closest(Selector.BUTTON)[0];
$$$1(button).toggleClass(ClassName.FOCUS, /^focus(in)?$/.test(event.type));
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = Button._jQueryInterface;
$$$1.fn[NAME].Constructor = Button;
$$$1.fn[NAME].noConflict = function () {
$$$1.fn[NAME] = JQUERY_NO_CONFLICT;
return Button._jQueryInterface;
};
return Button;
}($);
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0): carousel.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var Carousel = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'carousel';
var VERSION = '4.0.0';
var DATA_KEY = 'bs.carousel';
var EVENT_KEY = "." + DATA_KEY;
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var TRANSITION_DURATION = 600;
var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key
var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key
var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch
var Default = {
interval: 5000,
keyboard: true,
slide: false,
pause: 'hover',
wrap: true
};
var DefaultType = {
interval: '(number|boolean)',
keyboard: 'boolean',
slide: '(boolean|string)',
pause: '(string|boolean)',
wrap: 'boolean'
};
var Direction = {
NEXT: 'next',
PREV: 'prev',
LEFT: 'left',
RIGHT: 'right'
};
var Event = {
SLIDE: "slide" + EVENT_KEY,
SLID: "slid" + EVENT_KEY,
KEYDOWN: "keydown" + EVENT_KEY,
MOUSEENTER: "mouseenter" + EVENT_KEY,
MOUSELEAVE: "mouseleave" + EVENT_KEY,
TOUCHEND: "touchend" + EVENT_KEY,
LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY,
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
};
var ClassName = {
CAROUSEL: 'carousel',
ACTIVE: 'active',
SLIDE: 'slide',
RIGHT: 'carousel-item-right',
LEFT: 'carousel-item-left',
NEXT: 'carousel-item-next',
PREV: 'carousel-item-prev',
ITEM: 'carousel-item'
};
var Selector = {
ACTIVE: '.active',
ACTIVE_ITEM: '.active.carousel-item',
ITEM: '.carousel-item',
NEXT_PREV: '.carousel-item-next, .carousel-item-prev',
INDICATORS: '.carousel-indicators',
DATA_SLIDE: '[data-slide], [data-slide-to]',
DATA_RIDE: '[data-ride="carousel"]'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var Carousel =
/*#__PURE__*/
function () {
function Carousel(element, config) {
this._items = null;
this._interval = null;
this._activeElement = null;
this._isPaused = false;
this._isSliding = false;
this.touchTimeout = null;
this._config = this._getConfig(config);
this._element = $$$1(element)[0];
this._indicatorsElement = $$$1(this._element).find(Selector.INDICATORS)[0];
this._addEventListeners();
} // Getters
var _proto = Carousel.prototype;
// Public
_proto.next = function next() {
if (!this._isSliding) {
this._slide(Direction.NEXT);
}
};
_proto.nextWhenVisible = function nextWhenVisible() {
// Don't call next when the page isn't visible
// or the carousel or its parent isn't visible
if (!document.hidden && $$$1(this._element).is(':visible') && $$$1(this._element).css('visibility') !== 'hidden') {
this.next();
}
};
_proto.prev = function prev() {
if (!this._isSliding) {
this._slide(Direction.PREV);
}
};
_proto.pause = function pause(event) {
if (!event) {
this._isPaused = true;
}
if ($$$1(this._element).find(Selector.NEXT_PREV)[0] && Util.supportsTransitionEnd()) {
Util.triggerTransitionEnd(this._element);
this.cycle(true);
}
clearInterval(this._interval);
this._interval = null;
};
_proto.cycle = function cycle(event) {
if (!event) {
this._isPaused = false;
}
if (this._interval) {
clearInterval(this._interval);
this._interval = null;
}
if (this._config.interval && !this._isPaused) {
this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);
}
};
_proto.to = function to(index) {
var _this = this;
this._activeElement = $$$1(this._element).find(Selector.ACTIVE_ITEM)[0];
var activeIndex = this._getItemIndex(this._activeElement);
if (index > this._items.length - 1 || index < 0) {
return;
}
if (this._isSliding) {
$$$1(this._element).one(Event.SLID, function () {
return _this.to(index);
});
return;
}
if (activeIndex === index) {
this.pause();
this.cycle();
return;
}
var direction = index > activeIndex ? Direction.NEXT : Direction.PREV;
this._slide(direction, this._items[index]);
};
_proto.dispose = function dispose() {
$$$1(this._element).off(EVENT_KEY);
$$$1.removeData(this._element, DATA_KEY);
this._items = null;
this._config = null;
this._element = null;
this._interval = null;
this._isPaused = null;
this._isSliding = null;
this._activeElement = null;
this._indicatorsElement = null;
}; // Private
_proto._getConfig = function _getConfig(config) {
config = _extends({}, Default, config);
Util.typeCheckConfig(NAME, config, DefaultType);
return config;
};
_proto._addEventListeners = function _addEventListeners() {
var _this2 = this;
if (this._config.keyboard) {
$$$1(this._element).on(Event.KEYDOWN, function (event) {
return _this2._keydown(event);
});
}
if (this._config.pause === 'hover') {
$$$1(this._element).on(Event.MOUSEENTER, function (event) {
return _this2.pause(event);
}).on(Event.MOUSELEAVE, function (event) {
return _this2.cycle(event);
});
if ('ontouchstart' in document.documentElement) {
// If it's a touch-enabled device, mouseenter/leave are fired as
// part of the mouse compatibility events on first tap - the carousel
// would stop cycling until user tapped out of it;
// here, we listen for touchend, explicitly pause the carousel
// (as if it's the second time we tap on it, mouseenter compat event
// is NOT fired) and after a timeout (to allow for mouse compatibility
// events to fire) we explicitly restart cycling
$$$1(this._element).on(Event.TOUCHEND, function () {
_this2.pause();
if (_this2.touchTimeout) {
clearTimeout(_this2.touchTimeout);
}
_this2.touchTimeout = setTimeout(function (event) {
return _this2.cycle(event);
}, TOUCHEVENT_COMPAT_WAIT + _this2._config.interval);
});
}
}
};
_proto._keydown = function _keydown(event) {
if (/input|textarea/i.test(event.target.tagName)) {
return;
}
switch (event.which) {
case ARROW_LEFT_KEYCODE:
event.preventDefault();
this.prev();
break;
case ARROW_RIGHT_KEYCODE:
event.preventDefault();
this.next();
break;
default:
}
};
_proto._getItemIndex = function _getItemIndex(element) {
this._items = $$$1.makeArray($$$1(element).parent().find(Selector.ITEM));
return this._items.indexOf(element);
};
_proto._getItemByDirection = function _getItemByDirection(direction, activeElement) {
var isNextDirection = direction === Direction.NEXT;
var isPrevDirection = direction === Direction.PREV;
var activeIndex = this._getItemIndex(activeElement);
var lastItemIndex = this._items.length - 1;
var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;
if (isGoingToWrap && !this._config.wrap) {
return activeElement;
}
var delta = direction === Direction.PREV ? -1 : 1;
var itemIndex = (activeIndex + delta) % this._items.length;
return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];
};
_proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {
var targetIndex = this._getItemIndex(relatedTarget);
var fromIndex = this._getItemIndex($$$1(this._element).find(Selector.ACTIVE_ITEM)[0]);
var slideEvent = $$$1.Event(Event.SLIDE, {
relatedTarget: relatedTarget,
direction: eventDirectionName,
from: fromIndex,
to: targetIndex
});
$$$1(this._element).trigger(slideEvent);
return slideEvent;
};
_proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {
if (this._indicatorsElement) {
$$$1(this._indicatorsElement).find(Selector.ACTIVE).removeClass(ClassName.ACTIVE);
var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];
if (nextIndicator) {
$$$1(nextIndicator).addClass(ClassName.ACTIVE);
}
}
};
_proto._slide = function _slide(direction, element) {
var _this3 = this;
var activeElement = $$$1(this._element).find(Selector.ACTIVE_ITEM)[0];
var activeElementIndex = this._getItemIndex(activeElement);
var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);
var nextElementIndex = this._getItemIndex(nextElement);
var isCycling = Boolean(this._interval);
var directionalClassName;
var orderClassName;
var eventDirectionName;
if (direction === Direction.NEXT) {
directionalClassName = ClassName.LEFT;
orderClassName = ClassName.NEXT;
eventDirectionName = Direction.LEFT;
} else {
directionalClassName = ClassName.RIGHT;
orderClassName = ClassName.PREV;
eventDirectionName = Direction.RIGHT;
}
if (nextElement && $$$1(nextElement).hasClass(ClassName.ACTIVE)) {
this._isSliding = false;
return;
}
var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);
if (slideEvent.isDefaultPrevented()) {
return;
}
if (!activeElement || !nextElement) {
// Some weirdness is happening, so we bail
return;
}
this._isSliding = true;
if (isCycling) {
this.pause();
}
this._setActiveIndicatorElement(nextElement);
var slidEvent = $$$1.Event(Event.SLID, {
relatedTarget: nextElement,
direction: eventDirectionName,
from: activeElementIndex,
to: nextElementIndex
});
if (Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.SLIDE)) {
$$$1(nextElement).addClass(orderClassName);
Util.reflow(nextElement);
$$$1(activeElement).addClass(directionalClassName);
$$$1(nextElement).addClass(directionalClassName);
$$$1(activeElement).one(Util.TRANSITION_END, function () {
$$$1(nextElement).removeClass(directionalClassName + " " + orderClassName).addClass(ClassName.ACTIVE);
$$$1(activeElement).removeClass(ClassName.ACTIVE + " " + orderClassName + " " + directionalClassName);
_this3._isSliding = false;
setTimeout(function () {
return $$$1(_this3._element).trigger(slidEvent);
}, 0);
}).emulateTransitionEnd(TRANSITION_DURATION);
} else {
$$$1(activeElement).removeClass(ClassName.ACTIVE);
$$$1(nextElement).addClass(ClassName.ACTIVE);
this._isSliding = false;
$$$1(this._element).trigger(slidEvent);
}
if (isCycling) {
this.cycle();
}
}; // Static
Carousel._jQueryInterface = function _jQueryInterface(config) {
return this.each(function () {
var data = $$$1(this).data(DATA_KEY);
var _config = _extends({}, Default, $$$1(this).data());
if (typeof config === 'object') {
_config = _extends({}, _config, config);
}
var action = typeof config === 'string' ? config : _config.slide;
if (!data) {
data = new Carousel(this, _config);
$$$1(this).data(DATA_KEY, data);
}
if (typeof config === 'number') {
data.to(config);
} else if (typeof action === 'string') {
if (typeof data[action] === 'undefined') {
throw new TypeError("No method named \"" + action + "\"");
}
data[action]();
} else if (_config.interval) {
data.pause();
data.cycle();
}
});
};
Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {
var selector = Util.getSelectorFromElement(this);
if (!selector) {
return;
}
var target = $$$1(selector)[0];
if (!target || !$$$1(target).hasClass(ClassName.CAROUSEL)) {
return;
}
var config = _extends({}, $$$1(target).data(), $$$1(this).data());
var slideIndex = this.getAttribute('data-slide-to');
if (slideIndex) {
config.interval = false;
}
Carousel._jQueryInterface.call($$$1(target), config);
if (slideIndex) {
$$$1(target).data(DATA_KEY).to(slideIndex);
}
event.preventDefault();
};
_createClass(Carousel, null, [{
key: "VERSION",
get: function get() {
return VERSION;
}
}, {
key: "Default",
get: function get() {
return Default;
}
}]);
return Carousel;
}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
$$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler);
$$$1(window).on(Event.LOAD_DATA_API, function () {
$$$1(Selector.DATA_RIDE).each(function () {
var $carousel = $$$1(this);
Carousel._jQueryInterface.call($carousel, $carousel.data());
});
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = Carousel._jQueryInterface;
$$$1.fn[NAME].Constructor = Carousel;
$$$1.fn[NAME].noConflict = function () {
$$$1.fn[NAME] = JQUERY_NO_CONFLICT;
return Carousel._jQueryInterface;
};
return Carousel;
}($);
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0): collapse.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var Collapse = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'collapse';
var VERSION = '4.0.0';
var DATA_KEY = 'bs.collapse';
var EVENT_KEY = "." + DATA_KEY;
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var TRANSITION_DURATION = 600;
var Default = {
toggle: true,
parent: ''
};
var DefaultType = {
toggle: 'boolean',
parent: '(string|element)'
};
var Event = {
SHOW: "show" + EVENT_KEY,
SHOWN: "shown" + EVENT_KEY,
HIDE: "hide" + EVENT_KEY,
HIDDEN: "hidden" + EVENT_KEY,
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
};
var ClassName = {
SHOW: 'show',
COLLAPSE: 'collapse',
COLLAPSING: 'collapsing',
COLLAPSED: 'collapsed'
};
var Dimension = {
WIDTH: 'width',
HEIGHT: 'height'
};
var Selector = {
ACTIVES: '.show, .collapsing',
DATA_TOGGLE: '[data-toggle="collapse"]'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var Collapse =
/*#__PURE__*/
function () {
function Collapse(element, config) {
this._isTransitioning = false;
this._element = element;
this._config = this._getConfig(config);
this._triggerArray = $$$1.makeArray($$$1("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]")));
var tabToggles = $$$1(Selector.DATA_TOGGLE);
for (var i = 0; i < tabToggles.length; i++) {
var elem = tabToggles[i];
var selector = Util.getSelectorFromElement(elem);
if (selector !== null && $$$1(selector).filter(element).length > 0) {
this._selector = selector;
this._triggerArray.push(elem);
}
}
this._parent = this._config.parent ? this._getParent() : null;
if (!this._config.parent) {
this._addAriaAndCollapsedClass(this._element, this._triggerArray);
}
if (this._config.toggle) {
this.toggle();
}
} // Getters
var _proto = Collapse.prototype;
// Public
_proto.toggle = function toggle() {
if ($$$1(this._element).hasClass(ClassName.SHOW)) {
this.hide();
} else {
this.show();
}
};
_proto.show = function show() {
var _this = this;
if (this._isTransitioning || $$$1(this._element).hasClass(ClassName.SHOW)) {
return;
}
var actives;
var activesData;
if (this._parent) {
actives = $$$1.makeArray($$$1(this._parent).find(Selector.ACTIVES).filter("[data-parent=\"" + this._config.parent + "\"]"));
if (actives.length === 0) {
actives = null;
}
}
if (actives) {
activesData = $$$1(actives).not(this._selector).data(DATA_KEY);
if (activesData && activesData._isTransitioning) {
return;
}
}
var startEvent = $$$1.Event(Event.SHOW);
$$$1(this._element).trigger(startEvent);
if (startEvent.isDefaultPrevented()) {
return;
}
if (actives) {
Collapse._jQueryInterface.call($$$1(actives).not(this._selector), 'hide');
if (!activesData) {
$$$1(actives).data(DATA_KEY, null);
}
}
var dimension = this._getDimension();
$$$1(this._element).removeClass(ClassName.COLLAPSE).addClass(ClassName.COLLAPSING);
this._element.style[dimension] = 0;
if (this._triggerArray.length > 0) {
$$$1(this._triggerArray).removeClass(ClassName.COLLAPSED).attr('aria-expanded', true);
}
this.setTransitioning(true);
var complete = function complete() {
$$$1(_this._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).addClass(ClassName.SHOW);
_this._element.style[dimension] = '';
_this.setTransitioning(false);
$$$1(_this._element).trigger(Event.SHOWN);
};
if (!Util.supportsTransitionEnd()) {
complete();
return;
}
var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
var scrollSize = "scroll" + capitalizedDimension;
$$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
this._element.style[dimension] = this._element[scrollSize] + "px";
};
_proto.hide = function hide() {
var _this2 = this;
if (this._isTransitioning || !$$$1(this._element).hasClass(ClassName.SHOW)) {
return;
}
var startEvent = $$$1.Event(Event.HIDE);
$$$1(this._element).trigger(startEvent);
if (startEvent.isDefaultPrevented()) {
return;
}
var dimension = this._getDimension();
this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px";
Util.reflow(this._element);
$$$1(this._element).addClass(ClassName.COLLAPSING).removeClass(ClassName.COLLAPSE).removeClass(ClassName.SHOW);
if (this._triggerArray.length > 0) {
for (var i = 0; i < this._triggerArray.length; i++) {
var trigger = this._triggerArray[i];
var selector = Util.getSelectorFromElement(trigger);
if (selector !== null) {
var $elem = $$$1(selector);
if (!$elem.hasClass(ClassName.SHOW)) {
$$$1(trigger).addClass(ClassName.COLLAPSED).attr('aria-expanded', false);
}
}
}
}
this.setTransitioning(true);
var complete = function complete() {
_this2.setTransitioning(false);
$$$1(_this2._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).trigger(Event.HIDDEN);
};
this._element.style[dimension] = '';
if (!Util.supportsTransitionEnd()) {
complete();
return;
}
$$$1(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
};
_proto.setTransitioning = function setTransitioning(isTransitioning) {
this._isTransitioning = isTransitioning;
};
_proto.dispose = function dispose() {
$$$1.removeData(this._element, DATA_KEY);
this._config = null;
this._parent = null;
this._element = null;
this._triggerArray = null;
this._isTransitioning = null;
}; // Private
_proto._getConfig = function _getConfig(config) {
config = _extends({}, Default, config);
config.toggle = Boolean(config.toggle); // Coerce string values
Util.typeCheckConfig(NAME, config, DefaultType);
return config;
};
_proto._getDimension = function _getDimension() {
var hasWidth = $$$1(this._element).hasClass(Dimension.WIDTH);
return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT;
};
_proto._getParent = function _getParent() {
var _this3 = this;
var parent = null;
if (Util.isElement(this._config.parent)) {
parent = this._config.parent; // It's a jQuery object
if (typeof this._config.parent.jquery !== 'undefined') {
parent = this._config.parent[0];
}
} else {
parent = $$$1(this._config.parent)[0];
}
var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]";
$$$1(parent).find(selector).each(function (i, element) {
_this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);
});
return parent;
};
_proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {
if (element) {
var isOpen = $$$1(element).hasClass(ClassName.SHOW);
if (triggerArray.length > 0) {
$$$1(triggerArray).toggleClass(ClassName.COLLAPSED, !isOpen).attr('aria-expanded', isOpen);
}
}
}; // Static
Collapse._getTargetFromElement = function _getTargetFromElement(element) {
var selector = Util.getSelectorFromElement(element);
return selector ? $$$1(selector)[0] : null;
};
Collapse._jQueryInterface = function _jQueryInterface(config) {
return this.each(function () {
var $this = $$$1(this);
var data = $this.data(DATA_KEY);
var _config = _extends({}, Default, $this.data(), typeof config === 'object' && config);
if (!data && _config.toggle && /show|hide/.test(config)) {
_config.toggle = false;
}
if (!data) {
data = new Collapse(this, _config);
$this.data(DATA_KEY, data);
}
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError("No method named \"" + config + "\"");
}
data[config]();
}
});
};
_createClass(Collapse, null, [{
key: "VERSION",
get: function get() {
return VERSION;
}
}, {
key: "Default",
get: function get() {
return Default;
}
}]);
return Collapse;
}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
$$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
// preventDefault only for
elements (which change the URL) not inside the collapsible element
if (event.currentTarget.tagName === 'A') {
event.preventDefault();
}
var $trigger = $$$1(this);
var selector = Util.getSelectorFromElement(this);
$$$1(selector).each(function () {
var $target = $$$1(this);
var data = $target.data(DATA_KEY);
var config = data ? 'toggle' : $trigger.data();
Collapse._jQueryInterface.call($target, config);
});
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = Collapse._jQueryInterface;
$$$1.fn[NAME].Constructor = Collapse;
$$$1.fn[NAME].noConflict = function () {
$$$1.fn[NAME] = JQUERY_NO_CONFLICT;
return Collapse._jQueryInterface;
};
return Collapse;
}($);
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0): dropdown.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var Dropdown = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'dropdown';
var VERSION = '4.0.0';
var DATA_KEY = 'bs.dropdown';
var EVENT_KEY = "." + DATA_KEY;
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key
var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key
var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key
var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key
var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)
var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + "|" + ARROW_DOWN_KEYCODE + "|" + ESCAPE_KEYCODE);
var Event = {
HIDE: "hide" + EVENT_KEY,
HIDDEN: "hidden" + EVENT_KEY,
SHOW: "show" + EVENT_KEY,
SHOWN: "shown" + EVENT_KEY,
CLICK: "click" + EVENT_KEY,
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY,
KEYDOWN_DATA_API: "keydown" + EVENT_KEY + DATA_API_KEY,
KEYUP_DATA_API: "keyup" + EVENT_KEY + DATA_API_KEY
};
var ClassName = {
DISABLED: 'disabled',
SHOW: 'show',
DROPUP: 'dropup',
DROPRIGHT: 'dropright',
DROPLEFT: 'dropleft',
MENURIGHT: 'dropdown-menu-right',
MENULEFT: 'dropdown-menu-left',
POSITION_STATIC: 'position-static'
};
var Selector = {
DATA_TOGGLE: '[data-toggle="dropdown"]',
FORM_CHILD: '.dropdown form',
MENU: '.dropdown-menu',
NAVBAR_NAV: '.navbar-nav',
VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled)'
};
var AttachmentMap = {
TOP: 'top-start',
TOPEND: 'top-end',
BOTTOM: 'bottom-start',
BOTTOMEND: 'bottom-end',
RIGHT: 'right-start',
RIGHTEND: 'right-end',
LEFT: 'left-start',
LEFTEND: 'left-end'
};
var Default = {
offset: 0,
flip: true,
boundary: 'scrollParent'
};
var DefaultType = {
offset: '(number|string|function)',
flip: 'boolean',
boundary: '(string|element)'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var Dropdown =
/*#__PURE__*/
function () {
function Dropdown(element, config) {
this._element = element;
this._popper = null;
this._config = this._getConfig(config);
this._menu = this._getMenuElement();
this._inNavbar = this._detectNavbar();
this._addEventListeners();
} // Getters
var _proto = Dropdown.prototype;
// Public
_proto.toggle = function toggle() {
if (this._element.disabled || $$$1(this._element).hasClass(ClassName.DISABLED)) {
return;
}
var parent = Dropdown._getParentFromElement(this._element);
var isActive = $$$1(this._menu).hasClass(ClassName.SHOW);
Dropdown._clearMenus();
if (isActive) {
return;
}
var relatedTarget = {
relatedTarget: this._element
};
var showEvent = $$$1.Event(Event.SHOW, relatedTarget);
$$$1(parent).trigger(showEvent);
if (showEvent.isDefaultPrevented()) {
return;
} // Disable totally Popper.js for Dropdown in Navbar
if (!this._inNavbar) {
/**
* Check for Popper dependency
* Popper - https://popper.js.org
*/
if (typeof Popper === 'undefined') {
throw new TypeError('Bootstrap dropdown require Popper.js (https://popper.js.org)');
}
var element = this._element; // For dropup with alignment we use the parent as popper container
if ($$$1(parent).hasClass(ClassName.DROPUP)) {
if ($$$1(this._menu).hasClass(ClassName.MENULEFT) || $$$1(this._menu).hasClass(ClassName.MENURIGHT)) {
element = parent;
}
} // If boundary is not `scrollParent`, then set position to `static`
// to allow the menu to "escape" the scroll parent's boundaries
// https://github.com/twbs/bootstrap/issues/24251
if (this._config.boundary !== 'scrollParent') {
$$$1(parent).addClass(ClassName.POSITION_STATIC);
}
this._popper = new Popper(element, this._menu, this._getPopperConfig());
} // If this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
if ('ontouchstart' in document.documentElement && $$$1(parent).closest(Selector.NAVBAR_NAV).length === 0) {
$$$1('body').children().on('mouseover', null, $$$1.noop);
}
this._element.focus();
this._element.setAttribute('aria-expanded', true);
$$$1(this._menu).toggleClass(ClassName.SHOW);
$$$1(parent).toggleClass(ClassName.SHOW).trigger($$$1.Event(Event.SHOWN, relatedTarget));
};
_proto.dispose = function dispose() {
$$$1.removeData(this._element, DATA_KEY);
$$$1(this._element).off(EVENT_KEY);
this._element = null;
this._menu = null;
if (this._popper !== null) {
this._popper.destroy();
this._popper = null;
}
};
_proto.update = function update() {
this._inNavbar = this._detectNavbar();
if (this._popper !== null) {
this._popper.scheduleUpdate();
}
}; // Private
_proto._addEventListeners = function _addEventListeners() {
var _this = this;
$$$1(this._element).on(Event.CLICK, function (event) {
event.preventDefault();
event.stopPropagation();
_this.toggle();
});
};
_proto._getConfig = function _getConfig(config) {
config = _extends({}, this.constructor.Default, $$$1(this._element).data(), config);
Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);
return config;
};
_proto._getMenuElement = function _getMenuElement() {
if (!this._menu) {
var parent = Dropdown._getParentFromElement(this._element);
this._menu = $$$1(parent).find(Selector.MENU)[0];
}
return this._menu;
};
_proto._getPlacement = function _getPlacement() {
var $parentDropdown = $$$1(this._element).parent();
var placement = AttachmentMap.BOTTOM; // Handle dropup
if ($parentDropdown.hasClass(ClassName.DROPUP)) {
placement = AttachmentMap.TOP;
if ($$$1(this._menu).hasClass(ClassName.MENURIGHT)) {
placement = AttachmentMap.TOPEND;
}
} else if ($parentDropdown.hasClass(ClassName.DROPRIGHT)) {
placement = AttachmentMap.RIGHT;
} else if ($parentDropdown.hasClass(ClassName.DROPLEFT)) {
placement = AttachmentMap.LEFT;
} else if ($$$1(this._menu).hasClass(ClassName.MENURIGHT)) {
placement = AttachmentMap.BOTTOMEND;
}
return placement;
};
_proto._detectNavbar = function _detectNavbar() {
return $$$1(this._element).closest('.navbar').length > 0;
};
_proto._getPopperConfig = function _getPopperConfig() {
var _this2 = this;
var offsetConf = {};
if (typeof this._config.offset === 'function') {
offsetConf.fn = function (data) {
data.offsets = _extends({}, data.offsets, _this2._config.offset(data.offsets) || {});
return data;
};
} else {
offsetConf.offset = this._config.offset;
}
var popperConfig = {
placement: this._getPlacement(),
modifiers: {
offset: offsetConf,
flip: {
enabled: this._config.flip
},
preventOverflow: {
boundariesElement: this._config.boundary
}
}
};
return popperConfig;
}; // Static
Dropdown._jQueryInterface = function _jQueryInterface(config) {
return this.each(function () {
var data = $$$1(this).data(DATA_KEY);
var _config = typeof config === 'object' ? config : null;
if (!data) {
data = new Dropdown(this, _config);
$$$1(this).data(DATA_KEY, data);
}
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError("No method named \"" + config + "\"");
}
data[config]();
}
});
};
Dropdown._clearMenus = function _clearMenus(event) {
if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {
return;
}
var toggles = $$$1.makeArray($$$1(Selector.DATA_TOGGLE));
for (var i = 0; i < toggles.length; i++) {
var parent = Dropdown._getParentFromElement(toggles[i]);
var context = $$$1(toggles[i]).data(DATA_KEY);
var relatedTarget = {
relatedTarget: toggles[i]
};
if (!context) {
continue;
}
var dropdownMenu = context._menu;
if (!$$$1(parent).hasClass(ClassName.SHOW)) {
continue;
}
if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $$$1.contains(parent, event.target)) {
continue;
}
var hideEvent = $$$1.Event(Event.HIDE, relatedTarget);
$$$1(parent).trigger(hideEvent);
if (hideEvent.isDefaultPrevented()) {
continue;
} // If this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
if ('ontouchstart' in document.documentElement) {
$$$1('body').children().off('mouseover', null, $$$1.noop);
}
toggles[i].setAttribute('aria-expanded', 'false');
$$$1(dropdownMenu).removeClass(ClassName.SHOW);
$$$1(parent).removeClass(ClassName.SHOW).trigger($$$1.Event(Event.HIDDEN, relatedTarget));
}
};
Dropdown._getParentFromElement = function _getParentFromElement(element) {
var parent;
var selector = Util.getSelectorFromElement(element);
if (selector) {
parent = $$$1(selector)[0];
}
return parent || element.parentNode;
}; // eslint-disable-next-line complexity
Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {
// If not input/textarea:
// - And not a key in REGEXP_KEYDOWN => not a dropdown command
// If input/textarea:
// - If space key => not a dropdown command
// - If key is other than escape
// - If key is not up or down => not a dropdown command
// - If trigger inside the menu => not a dropdown command
if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $$$1(event.target).closest(Selector.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {
return;
}
event.preventDefault();
event.stopPropagation();
if (this.disabled || $$$1(this).hasClass(ClassName.DISABLED)) {
return;
}
var parent = Dropdown._getParentFromElement(this);
var isActive = $$$1(parent).hasClass(ClassName.SHOW);
if (!isActive && (event.which !== ESCAPE_KEYCODE || event.which !== SPACE_KEYCODE) || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {
if (event.which === ESCAPE_KEYCODE) {
var toggle = $$$1(parent).find(Selector.DATA_TOGGLE)[0];
$$$1(toggle).trigger('focus');
}
$$$1(this).trigger('click');
return;
}
var items = $$$1(parent).find(Selector.VISIBLE_ITEMS).get();
if (items.length === 0) {
return;
}
var index = items.indexOf(event.target);
if (event.which === ARROW_UP_KEYCODE && index > 0) {
// Up
index--;
}
if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {
// Down
index++;
}
if (index < 0) {
index = 0;
}
items[index].focus();
};
_createClass(Dropdown, null, [{
key: "VERSION",
get: function get() {
return VERSION;
}
}, {
key: "Default",
get: function get() {
return Default;
}
}, {
key: "DefaultType",
get: function get() {
return DefaultType;
}
}]);
return Dropdown;
}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
$$$1(document).on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API + " " + Event.KEYUP_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
event.preventDefault();
event.stopPropagation();
Dropdown._jQueryInterface.call($$$1(this), 'toggle');
}).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) {
e.stopPropagation();
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = Dropdown._jQueryInterface;
$$$1.fn[NAME].Constructor = Dropdown;
$$$1.fn[NAME].noConflict = function () {
$$$1.fn[NAME] = JQUERY_NO_CONFLICT;
return Dropdown._jQueryInterface;
};
return Dropdown;
}($, Popper);
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0): modal.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var Modal = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'modal';
var VERSION = '4.0.0';
var DATA_KEY = 'bs.modal';
var EVENT_KEY = "." + DATA_KEY;
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var TRANSITION_DURATION = 300;
var BACKDROP_TRANSITION_DURATION = 150;
var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
var Default = {
backdrop: true,
keyboard: true,
focus: true,
show: true
};
var DefaultType = {
backdrop: '(boolean|string)',
keyboard: 'boolean',
focus: 'boolean',
show: 'boolean'
};
var Event = {
HIDE: "hide" + EVENT_KEY,
HIDDEN: "hidden" + EVENT_KEY,
SHOW: "show" + EVENT_KEY,
SHOWN: "shown" + EVENT_KEY,
FOCUSIN: "focusin" + EVENT_KEY,
RESIZE: "resize" + EVENT_KEY,
CLICK_DISMISS: "click.dismiss" + EVENT_KEY,
KEYDOWN_DISMISS: "keydown.dismiss" + EVENT_KEY,
MOUSEUP_DISMISS: "mouseup.dismiss" + EVENT_KEY,
MOUSEDOWN_DISMISS: "mousedown.dismiss" + EVENT_KEY,
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
};
var ClassName = {
SCROLLBAR_MEASURER: 'modal-scrollbar-measure',
BACKDROP: 'modal-backdrop',
OPEN: 'modal-open',
FADE: 'fade',
SHOW: 'show'
};
var Selector = {
DIALOG: '.modal-dialog',
DATA_TOGGLE: '[data-toggle="modal"]',
DATA_DISMISS: '[data-dismiss="modal"]',
FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
STICKY_CONTENT: '.sticky-top',
NAVBAR_TOGGLER: '.navbar-toggler'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var Modal =
/*#__PURE__*/
function () {
function Modal(element, config) {
this._config = this._getConfig(config);
this._element = element;
this._dialog = $$$1(element).find(Selector.DIALOG)[0];
this._backdrop = null;
this._isShown = false;
this._isBodyOverflowing = false;
this._ignoreBackdropClick = false;
this._originalBodyPadding = 0;
this._scrollbarWidth = 0;
} // Getters
var _proto = Modal.prototype;
// Public
_proto.toggle = function toggle(relatedTarget) {
return this._isShown ? this.hide() : this.show(relatedTarget);
};
_proto.show = function show(relatedTarget) {
var _this = this;
if (this._isTransitioning || this._isShown) {
return;
}
if (Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE)) {
this._isTransitioning = true;
}
var showEvent = $$$1.Event(Event.SHOW, {
relatedTarget: relatedTarget
});
$$$1(this._element).trigger(showEvent);
if (this._isShown || showEvent.isDefaultPrevented()) {
return;
}
this._isShown = true;
this._checkScrollbar();
this._setScrollbar();
this._adjustDialog();
$$$1(document.body).addClass(ClassName.OPEN);
this._setEscapeEvent();
this._setResizeEvent();
$$$1(this._element).on(Event.CLICK_DISMISS, Selector.DATA_DISMISS, function (event) {
return _this.hide(event);
});
$$$1(this._dialog).on(Event.MOUSEDOWN_DISMISS, function () {
$$$1(_this._element).one(Event.MOUSEUP_DISMISS, function (event) {
if ($$$1(event.target).is(_this._element)) {
_this._ignoreBackdropClick = true;
}
});
});
this._showBackdrop(function () {
return _this._showElement(relatedTarget);
});
};
_proto.hide = function hide(event) {
var _this2 = this;
if (event) {
event.preventDefault();
}
if (this._isTransitioning || !this._isShown) {
return;
}
var hideEvent = $$$1.Event(Event.HIDE);
$$$1(this._element).trigger(hideEvent);
if (!this._isShown || hideEvent.isDefaultPrevented()) {
return;
}
this._isShown = false;
var transition = Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE);
if (transition) {
this._isTransitioning = true;
}
this._setEscapeEvent();
this._setResizeEvent();
$$$1(document).off(Event.FOCUSIN);
$$$1(this._element).removeClass(ClassName.SHOW);
$$$1(this._element).off(Event.CLICK_DISMISS);
$$$1(this._dialog).off(Event.MOUSEDOWN_DISMISS);
if (transition) {
$$$1(this._element).one(Util.TRANSITION_END, function (event) {
return _this2._hideModal(event);
}).emulateTransitionEnd(TRANSITION_DURATION);
} else {
this._hideModal();
}
};
_proto.dispose = function dispose() {
$$$1.removeData(this._element, DATA_KEY);
$$$1(window, document, this._element, this._backdrop).off(EVENT_KEY);
this._config = null;
this._element = null;
this._dialog = null;
this._backdrop = null;
this._isShown = null;
this._isBodyOverflowing = null;
this._ignoreBackdropClick = null;
this._scrollbarWidth = null;
};
_proto.handleUpdate = function handleUpdate() {
this._adjustDialog();
}; // Private
_proto._getConfig = function _getConfig(config) {
config = _extends({}, Default, config);
Util.typeCheckConfig(NAME, config, DefaultType);
return config;
};
_proto._showElement = function _showElement(relatedTarget) {
var _this3 = this;
var transition = Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE);
if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
// Don't move modal's DOM position
document.body.appendChild(this._element);
}
this._element.style.display = 'block';
this._element.removeAttribute('aria-hidden');
this._element.scrollTop = 0;
if (transition) {
Util.reflow(this._element);
}
$$$1(this._element).addClass(ClassName.SHOW);
if (this._config.focus) {
this._enforceFocus();
}
var shownEvent = $$$1.Event(Event.SHOWN, {
relatedTarget: relatedTarget
});
var transitionComplete = function transitionComplete() {
if (_this3._config.focus) {
_this3._element.focus();
}
_this3._isTransitioning = false;
$$$1(_this3._element).trigger(shownEvent);
};
if (transition) {
$$$1(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(TRANSITION_DURATION);
} else {
transitionComplete();
}
};
_proto._enforceFocus = function _enforceFocus() {
var _this4 = this;
$$$1(document).off(Event.FOCUSIN) // Guard against infinite focus loop
.on(Event.FOCUSIN, function (event) {
if (document !== event.target && _this4._element !== event.target && $$$1(_this4._element).has(event.target).length === 0) {
_this4._element.focus();
}
});
};
_proto._setEscapeEvent = function _setEscapeEvent() {
var _this5 = this;
if (this._isShown && this._config.keyboard) {
$$$1(this._element).on(Event.KEYDOWN_DISMISS, function (event) {
if (event.which === ESCAPE_KEYCODE) {
event.preventDefault();
_this5.hide();
}
});
} else if (!this._isShown) {
$$$1(this._element).off(Event.KEYDOWN_DISMISS);
}
};
_proto._setResizeEvent = function _setResizeEvent() {
var _this6 = this;
if (this._isShown) {
$$$1(window).on(Event.RESIZE, function (event) {
return _this6.handleUpdate(event);
});
} else {
$$$1(window).off(Event.RESIZE);
}
};
_proto._hideModal = function _hideModal() {
var _this7 = this;
this._element.style.display = 'none';
this._element.setAttribute('aria-hidden', true);
this._isTransitioning = false;
this._showBackdrop(function () {
$$$1(document.body).removeClass(ClassName.OPEN);
_this7._resetAdjustments();
_this7._resetScrollbar();
$$$1(_this7._element).trigger(Event.HIDDEN);
});
};
_proto._removeBackdrop = function _removeBackdrop() {
if (this._backdrop) {
$$$1(this._backdrop).remove();
this._backdrop = null;
}
};
_proto._showBackdrop = function _showBackdrop(callback) {
var _this8 = this;
var animate = $$$1(this._element).hasClass(ClassName.FADE) ? ClassName.FADE : '';
if (this._isShown && this._config.backdrop) {
var doAnimate = Util.supportsTransitionEnd() && animate;
this._backdrop = document.createElement('div');
this._backdrop.className = ClassName.BACKDROP;
if (animate) {
$$$1(this._backdrop).addClass(animate);
}
$$$1(this._backdrop).appendTo(document.body);
$$$1(this._element).on(Event.CLICK_DISMISS, function (event) {
if (_this8._ignoreBackdropClick) {
_this8._ignoreBackdropClick = false;
return;
}
if (event.target !== event.currentTarget) {
return;
}
if (_this8._config.backdrop === 'static') {
_this8._element.focus();
} else {
_this8.hide();
}
});
if (doAnimate) {
Util.reflow(this._backdrop);
}
$$$1(this._backdrop).addClass(ClassName.SHOW);
if (!callback) {
return;
}
if (!doAnimate) {
callback();
return;
}
$$$1(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(BACKDROP_TRANSITION_DURATION);
} else if (!this._isShown && this._backdrop) {
$$$1(this._backdrop).removeClass(ClassName.SHOW);
var callbackRemove = function callbackRemove() {
_this8._removeBackdrop();
if (callback) {
callback();
}
};
if (Util.supportsTransitionEnd() && $$$1(this._element).hasClass(ClassName.FADE)) {
$$$1(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(BACKDROP_TRANSITION_DURATION);
} else {
callbackRemove();
}
} else if (callback) {
callback();
}
}; // ----------------------------------------------------------------------
// the following methods are used to handle overflowing modals
// todo (fat): these should probably be refactored out of modal.js
// ----------------------------------------------------------------------
_proto._adjustDialog = function _adjustDialog() {
var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
if (!this._isBodyOverflowing && isModalOverflowing) {
this._element.style.paddingLeft = this._scrollbarWidth + "px";
}
if (this._isBodyOverflowing && !isModalOverflowing) {
this._element.style.paddingRight = this._scrollbarWidth + "px";
}
};
_proto._resetAdjustments = function _resetAdjustments() {
this._element.style.paddingLeft = '';
this._element.style.paddingRight = '';
};
_proto._checkScrollbar = function _checkScrollbar() {
var rect = document.body.getBoundingClientRect();
this._isBodyOverflowing = rect.left + rect.right < window.innerWidth;
this._scrollbarWidth = this._getScrollbarWidth();
};
_proto._setScrollbar = function _setScrollbar() {
var _this9 = this;
if (this._isBodyOverflowing) {
// Note: DOMNode.style.paddingRight returns the actual value or '' if not set
// while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
// Adjust fixed content padding
$$$1(Selector.FIXED_CONTENT).each(function (index, element) {
var actualPadding = $$$1(element)[0].style.paddingRight;
var calculatedPadding = $$$1(element).css('padding-right');
$$$1(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this9._scrollbarWidth + "px");
}); // Adjust sticky content margin
$$$1(Selector.STICKY_CONTENT).each(function (index, element) {
var actualMargin = $$$1(element)[0].style.marginRight;
var calculatedMargin = $$$1(element).css('margin-right');
$$$1(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this9._scrollbarWidth + "px");
}); // Adjust navbar-toggler margin
$$$1(Selector.NAVBAR_TOGGLER).each(function (index, element) {
var actualMargin = $$$1(element)[0].style.marginRight;
var calculatedMargin = $$$1(element).css('margin-right');
$$$1(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) + _this9._scrollbarWidth + "px");
}); // Adjust body padding
var actualPadding = document.body.style.paddingRight;
var calculatedPadding = $$$1('body').css('padding-right');
$$$1('body').data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + "px");
}
};
_proto._resetScrollbar = function _resetScrollbar() {
// Restore fixed content padding
$$$1(Selector.FIXED_CONTENT).each(function (index, element) {
var padding = $$$1(element).data('padding-right');
if (typeof padding !== 'undefined') {
$$$1(element).css('padding-right', padding).removeData('padding-right');
}
}); // Restore sticky content and navbar-toggler margin
$$$1(Selector.STICKY_CONTENT + ", " + Selector.NAVBAR_TOGGLER).each(function (index, element) {
var margin = $$$1(element).data('margin-right');
if (typeof margin !== 'undefined') {
$$$1(element).css('margin-right', margin).removeData('margin-right');
}
}); // Restore body padding
var padding = $$$1('body').data('padding-right');
if (typeof padding !== 'undefined') {
$$$1('body').css('padding-right', padding).removeData('padding-right');
}
};
_proto._getScrollbarWidth = function _getScrollbarWidth() {
// thx d.walsh
var scrollDiv = document.createElement('div');
scrollDiv.className = ClassName.SCROLLBAR_MEASURER;
document.body.appendChild(scrollDiv);
var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
document.body.removeChild(scrollDiv);
return scrollbarWidth;
}; // Static
Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) {
return this.each(function () {
var data = $$$1(this).data(DATA_KEY);
var _config = _extends({}, Modal.Default, $$$1(this).data(), typeof config === 'object' && config);
if (!data) {
data = new Modal(this, _config);
$$$1(this).data(DATA_KEY, data);
}
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError("No method named \"" + config + "\"");
}
data[config](relatedTarget);
} else if (_config.show) {
data.show(relatedTarget);
}
});
};
_createClass(Modal, null, [{
key: "VERSION",
get: function get() {
return VERSION;
}
}, {
key: "Default",
get: function get() {
return Default;
}
}]);
return Modal;
}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
$$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
var _this10 = this;
var target;
var selector = Util.getSelectorFromElement(this);
if (selector) {
target = $$$1(selector)[0];
}
var config = $$$1(target).data(DATA_KEY) ? 'toggle' : _extends({}, $$$1(target).data(), $$$1(this).data());
if (this.tagName === 'A' || this.tagName === 'AREA') {
event.preventDefault();
}
var $target = $$$1(target).one(Event.SHOW, function (showEvent) {
if (showEvent.isDefaultPrevented()) {
// Only register focus restorer if modal will actually get shown
return;
}
$target.one(Event.HIDDEN, function () {
if ($$$1(_this10).is(':visible')) {
_this10.focus();
}
});
});
Modal._jQueryInterface.call($$$1(target), config, this);
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = Modal._jQueryInterface;
$$$1.fn[NAME].Constructor = Modal;
$$$1.fn[NAME].noConflict = function () {
$$$1.fn[NAME] = JQUERY_NO_CONFLICT;
return Modal._jQueryInterface;
};
return Modal;
}($);
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0): tooltip.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var Tooltip = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'tooltip';
var VERSION = '4.0.0';
var DATA_KEY = 'bs.tooltip';
var EVENT_KEY = "." + DATA_KEY;
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var TRANSITION_DURATION = 150;
var CLASS_PREFIX = 'bs-tooltip';
var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g');
var DefaultType = {
animation: 'boolean',
template: 'string',
title: '(string|element|function)',
trigger: 'string',
delay: '(number|object)',
html: 'boolean',
selector: '(string|boolean)',
placement: '(string|function)',
offset: '(number|string)',
container: '(string|element|boolean)',
fallbackPlacement: '(string|array)',
boundary: '(string|element)'
};
var AttachmentMap = {
AUTO: 'auto',
TOP: 'top',
RIGHT: 'right',
BOTTOM: 'bottom',
LEFT: 'left'
};
var Default = {
animation: true,
template: '',
trigger: 'hover focus',
title: '',
delay: 0,
html: false,
selector: false,
placement: 'top',
offset: 0,
container: false,
fallbackPlacement: 'flip',
boundary: 'scrollParent'
};
var HoverState = {
SHOW: 'show',
OUT: 'out'
};
var Event = {
HIDE: "hide" + EVENT_KEY,
HIDDEN: "hidden" + EVENT_KEY,
SHOW: "show" + EVENT_KEY,
SHOWN: "shown" + EVENT_KEY,
INSERTED: "inserted" + EVENT_KEY,
CLICK: "click" + EVENT_KEY,
FOCUSIN: "focusin" + EVENT_KEY,
FOCUSOUT: "focusout" + EVENT_KEY,
MOUSEENTER: "mouseenter" + EVENT_KEY,
MOUSELEAVE: "mouseleave" + EVENT_KEY
};
var ClassName = {
FADE: 'fade',
SHOW: 'show'
};
var Selector = {
TOOLTIP: '.tooltip',
TOOLTIP_INNER: '.tooltip-inner',
ARROW: '.arrow'
};
var Trigger = {
HOVER: 'hover',
FOCUS: 'focus',
CLICK: 'click',
MANUAL: 'manual'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var Tooltip =
/*#__PURE__*/
function () {
function Tooltip(element, config) {
/**
* Check for Popper dependency
* Popper - https://popper.js.org
*/
if (typeof Popper === 'undefined') {
throw new TypeError('Bootstrap tooltips require Popper.js (https://popper.js.org)');
} // private
this._isEnabled = true;
this._timeout = 0;
this._hoverState = '';
this._activeTrigger = {};
this._popper = null; // Protected
this.element = element;
this.config = this._getConfig(config);
this.tip = null;
this._setListeners();
} // Getters
var _proto = Tooltip.prototype;
// Public
_proto.enable = function enable() {
this._isEnabled = true;
};
_proto.disable = function disable() {
this._isEnabled = false;
};
_proto.toggleEnabled = function toggleEnabled() {
this._isEnabled = !this._isEnabled;
};
_proto.toggle = function toggle(event) {
if (!this._isEnabled) {
return;
}
if (event) {
var dataKey = this.constructor.DATA_KEY;
var context = $$$1(event.currentTarget).data(dataKey);
if (!context) {
context = new this.constructor(event.currentTarget, this._getDelegateConfig());
$$$1(event.currentTarget).data(dataKey, context);
}
context._activeTrigger.click = !context._activeTrigger.click;
if (context._isWithActiveTrigger()) {
context._enter(null, context);
} else {
context._leave(null, context);
}
} else {
if ($$$1(this.getTipElement()).hasClass(ClassName.SHOW)) {
this._leave(null, this);
return;
}
this._enter(null, this);
}
};
_proto.dispose = function dispose() {
clearTimeout(this._timeout);
$$$1.removeData(this.element, this.constructor.DATA_KEY);
$$$1(this.element).off(this.constructor.EVENT_KEY);
$$$1(this.element).closest('.modal').off('hide.bs.modal');
if (this.tip) {
$$$1(this.tip).remove();
}
this._isEnabled = null;
this._timeout = null;
this._hoverState = null;
this._activeTrigger = null;
if (this._popper !== null) {
this._popper.destroy();
}
this._popper = null;
this.element = null;
this.config = null;
this.tip = null;
};
_proto.show = function show() {
var _this = this;
if ($$$1(this.element).css('display') === 'none') {
throw new Error('Please use show on visible elements');
}
var showEvent = $$$1.Event(this.constructor.Event.SHOW);
if (this.isWithContent() && this._isEnabled) {
$$$1(this.element).trigger(showEvent);
var isInTheDom = $$$1.contains(this.element.ownerDocument.documentElement, this.element);
if (showEvent.isDefaultPrevented() || !isInTheDom) {
return;
}
var tip = this.getTipElement();
var tipId = Util.getUID(this.constructor.NAME);
tip.setAttribute('id', tipId);
this.element.setAttribute('aria-describedby', tipId);
this.setContent();
if (this.config.animation) {
$$$1(tip).addClass(ClassName.FADE);
}
var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;
var attachment = this._getAttachment(placement);
this.addAttachmentClass(attachment);
var container = this.config.container === false ? document.body : $$$1(this.config.container);
$$$1(tip).data(this.constructor.DATA_KEY, this);
if (!$$$1.contains(this.element.ownerDocument.documentElement, this.tip)) {
$$$1(tip).appendTo(container);
}
$$$1(this.element).trigger(this.constructor.Event.INSERTED);
this._popper = new Popper(this.element, tip, {
placement: attachment,
modifiers: {
offset: {
offset: this.config.offset
},
flip: {
behavior: this.config.fallbackPlacement
},
arrow: {
element: Selector.ARROW
},
preventOverflow: {
boundariesElement: this.config.boundary
}
},
onCreate: function onCreate(data) {
if (data.originalPlacement !== data.placement) {
_this._handlePopperPlacementChange(data);
}
},
onUpdate: function onUpdate(data) {
_this._handlePopperPlacementChange(data);
}
});
$$$1(tip).addClass(ClassName.SHOW); // If this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
if ('ontouchstart' in document.documentElement) {
$$$1('body').children().on('mouseover', null, $$$1.noop);
}
var complete = function complete() {
if (_this.config.animation) {
_this._fixTransition();
}
var prevHoverState = _this._hoverState;
_this._hoverState = null;
$$$1(_this.element).trigger(_this.constructor.Event.SHOWN);
if (prevHoverState === HoverState.OUT) {
_this._leave(null, _this);
}
};
if (Util.supportsTransitionEnd() && $$$1(this.tip).hasClass(ClassName.FADE)) {
$$$1(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(Tooltip._TRANSITION_DURATION);
} else {
complete();
}
}
};
_proto.hide = function hide(callback) {
var _this2 = this;
var tip = this.getTipElement();
var hideEvent = $$$1.Event(this.constructor.Event.HIDE);
var complete = function complete() {
if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) {
tip.parentNode.removeChild(tip);
}
_this2._cleanTipClass();
_this2.element.removeAttribute('aria-describedby');
$$$1(_this2.element).trigger(_this2.constructor.Event.HIDDEN);
if (_this2._popper !== null) {
_this2._popper.destroy();
}
if (callback) {
callback();
}
};
$$$1(this.element).trigger(hideEvent);
if (hideEvent.isDefaultPrevented()) {
return;
}
$$$1(tip).removeClass(ClassName.SHOW); // If this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
if ('ontouchstart' in document.documentElement) {
$$$1('body').children().off('mouseover', null, $$$1.noop);
}
this._activeTrigger[Trigger.CLICK] = false;
this._activeTrigger[Trigger.FOCUS] = false;
this._activeTrigger[Trigger.HOVER] = false;
if (Util.supportsTransitionEnd() && $$$1(this.tip).hasClass(ClassName.FADE)) {
$$$1(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
} else {
complete();
}
this._hoverState = '';
};
_proto.update = function update() {
if (this._popper !== null) {
this._popper.scheduleUpdate();
}
}; // Protected
_proto.isWithContent = function isWithContent() {
return Boolean(this.getTitle());
};
_proto.addAttachmentClass = function addAttachmentClass(attachment) {
$$$1(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment);
};
_proto.getTipElement = function getTipElement() {
this.tip = this.tip || $$$1(this.config.template)[0];
return this.tip;
};
_proto.setContent = function setContent() {
var $tip = $$$1(this.getTipElement());
this.setElementContent($tip.find(Selector.TOOLTIP_INNER), this.getTitle());
$tip.removeClass(ClassName.FADE + " " + ClassName.SHOW);
};
_proto.setElementContent = function setElementContent($element, content) {
var html = this.config.html;
if (typeof content === 'object' && (content.nodeType || content.jquery)) {
// Content is a DOM node or a jQuery
if (html) {
if (!$$$1(content).parent().is($element)) {
$element.empty().append(content);
}
} else {
$element.text($$$1(content).text());
}
} else {
$element[html ? 'html' : 'text'](content);
}
};
_proto.getTitle = function getTitle() {
var title = this.element.getAttribute('data-original-title');
if (!title) {
title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;
}
return title;
}; // Private
_proto._getAttachment = function _getAttachment(placement) {
return AttachmentMap[placement.toUpperCase()];
};
_proto._setListeners = function _setListeners() {
var _this3 = this;
var triggers = this.config.trigger.split(' ');
triggers.forEach(function (trigger) {
if (trigger === 'click') {
$$$1(_this3.element).on(_this3.constructor.Event.CLICK, _this3.config.selector, function (event) {
return _this3.toggle(event);
});
} else if (trigger !== Trigger.MANUAL) {
var eventIn = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSEENTER : _this3.constructor.Event.FOCUSIN;
var eventOut = trigger === Trigger.HOVER ? _this3.constructor.Event.MOUSELEAVE : _this3.constructor.Event.FOCUSOUT;
$$$1(_this3.element).on(eventIn, _this3.config.selector, function (event) {
return _this3._enter(event);
}).on(eventOut, _this3.config.selector, function (event) {
return _this3._leave(event);
});
}
$$$1(_this3.element).closest('.modal').on('hide.bs.modal', function () {
return _this3.hide();
});
});
if (this.config.selector) {
this.config = _extends({}, this.config, {
trigger: 'manual',
selector: ''
});
} else {
this._fixTitle();
}
};
_proto._fixTitle = function _fixTitle() {
var titleType = typeof this.element.getAttribute('data-original-title');
if (this.element.getAttribute('title') || titleType !== 'string') {
this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');
this.element.setAttribute('title', '');
}
};
_proto._enter = function _enter(event, context) {
var dataKey = this.constructor.DATA_KEY;
context = context || $$$1(event.currentTarget).data(dataKey);
if (!context) {
context = new this.constructor(event.currentTarget, this._getDelegateConfig());
$$$1(event.currentTarget).data(dataKey, context);
}
if (event) {
context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true;
}
if ($$$1(context.getTipElement()).hasClass(ClassName.SHOW) || context._hoverState === HoverState.SHOW) {
context._hoverState = HoverState.SHOW;
return;
}
clearTimeout(context._timeout);
context._hoverState = HoverState.SHOW;
if (!context.config.delay || !context.config.delay.show) {
context.show();
return;
}
context._timeout = setTimeout(function () {
if (context._hoverState === HoverState.SHOW) {
context.show();
}
}, context.config.delay.show);
};
_proto._leave = function _leave(event, context) {
var dataKey = this.constructor.DATA_KEY;
context = context || $$$1(event.currentTarget).data(dataKey);
if (!context) {
context = new this.constructor(event.currentTarget, this._getDelegateConfig());
$$$1(event.currentTarget).data(dataKey, context);
}
if (event) {
context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false;
}
if (context._isWithActiveTrigger()) {
return;
}
clearTimeout(context._timeout);
context._hoverState = HoverState.OUT;
if (!context.config.delay || !context.config.delay.hide) {
context.hide();
return;
}
context._timeout = setTimeout(function () {
if (context._hoverState === HoverState.OUT) {
context.hide();
}
}, context.config.delay.hide);
};
_proto._isWithActiveTrigger = function _isWithActiveTrigger() {
for (var trigger in this._activeTrigger) {
if (this._activeTrigger[trigger]) {
return true;
}
}
return false;
};
_proto._getConfig = function _getConfig(config) {
config = _extends({}, this.constructor.Default, $$$1(this.element).data(), config);
if (typeof config.delay === 'number') {
config.delay = {
show: config.delay,
hide: config.delay
};
}
if (typeof config.title === 'number') {
config.title = config.title.toString();
}
if (typeof config.content === 'number') {
config.content = config.content.toString();
}
Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);
return config;
};
_proto._getDelegateConfig = function _getDelegateConfig() {
var config = {};
if (this.config) {
for (var key in this.config) {
if (this.constructor.Default[key] !== this.config[key]) {
config[key] = this.config[key];
}
}
}
return config;
};
_proto._cleanTipClass = function _cleanTipClass() {
var $tip = $$$1(this.getTipElement());
var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);
if (tabClass !== null && tabClass.length > 0) {
$tip.removeClass(tabClass.join(''));
}
};
_proto._handlePopperPlacementChange = function _handlePopperPlacementChange(data) {
this._cleanTipClass();
this.addAttachmentClass(this._getAttachment(data.placement));
};
_proto._fixTransition = function _fixTransition() {
var tip = this.getTipElement();
var initConfigAnimation = this.config.animation;
if (tip.getAttribute('x-placement') !== null) {
return;
}
$$$1(tip).removeClass(ClassName.FADE);
this.config.animation = false;
this.hide();
this.show();
this.config.animation = initConfigAnimation;
}; // Static
Tooltip._jQueryInterface = function _jQueryInterface(config) {
return this.each(function () {
var data = $$$1(this).data(DATA_KEY);
var _config = typeof config === 'object' && config;
if (!data && /dispose|hide/.test(config)) {
return;
}
if (!data) {
data = new Tooltip(this, _config);
$$$1(this).data(DATA_KEY, data);
}
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError("No method named \"" + config + "\"");
}
data[config]();
}
});
};
_createClass(Tooltip, null, [{
key: "VERSION",
get: function get() {
return VERSION;
}
}, {
key: "Default",
get: function get() {
return Default;
}
}, {
key: "NAME",
get: function get() {
return NAME;
}
}, {
key: "DATA_KEY",
get: function get() {
return DATA_KEY;
}
}, {
key: "Event",
get: function get() {
return Event;
}
}, {
key: "EVENT_KEY",
get: function get() {
return EVENT_KEY;
}
}, {
key: "DefaultType",
get: function get() {
return DefaultType;
}
}]);
return Tooltip;
}();
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = Tooltip._jQueryInterface;
$$$1.fn[NAME].Constructor = Tooltip;
$$$1.fn[NAME].noConflict = function () {
$$$1.fn[NAME] = JQUERY_NO_CONFLICT;
return Tooltip._jQueryInterface;
};
return Tooltip;
}($, Popper);
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0): popover.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var Popover = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'popover';
var VERSION = '4.0.0';
var DATA_KEY = 'bs.popover';
var EVENT_KEY = "." + DATA_KEY;
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var CLASS_PREFIX = 'bs-popover';
var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g');
var Default = _extends({}, Tooltip.Default, {
placement: 'right',
trigger: 'click',
content: '',
template: ''
});
var DefaultType = _extends({}, Tooltip.DefaultType, {
content: '(string|element|function)'
});
var ClassName = {
FADE: 'fade',
SHOW: 'show'
};
var Selector = {
TITLE: '.popover-header',
CONTENT: '.popover-body'
};
var Event = {
HIDE: "hide" + EVENT_KEY,
HIDDEN: "hidden" + EVENT_KEY,
SHOW: "show" + EVENT_KEY,
SHOWN: "shown" + EVENT_KEY,
INSERTED: "inserted" + EVENT_KEY,
CLICK: "click" + EVENT_KEY,
FOCUSIN: "focusin" + EVENT_KEY,
FOCUSOUT: "focusout" + EVENT_KEY,
MOUSEENTER: "mouseenter" + EVENT_KEY,
MOUSELEAVE: "mouseleave" + EVENT_KEY
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var Popover =
/*#__PURE__*/
function (_Tooltip) {
_inheritsLoose(Popover, _Tooltip);
function Popover() {
return _Tooltip.apply(this, arguments) || this;
}
var _proto = Popover.prototype;
// Overrides
_proto.isWithContent = function isWithContent() {
return this.getTitle() || this._getContent();
};
_proto.addAttachmentClass = function addAttachmentClass(attachment) {
$$$1(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment);
};
_proto.getTipElement = function getTipElement() {
this.tip = this.tip || $$$1(this.config.template)[0];
return this.tip;
};
_proto.setContent = function setContent() {
var $tip = $$$1(this.getTipElement()); // We use append for html objects to maintain js events
this.setElementContent($tip.find(Selector.TITLE), this.getTitle());
var content = this._getContent();
if (typeof content === 'function') {
content = content.call(this.element);
}
this.setElementContent($tip.find(Selector.CONTENT), content);
$tip.removeClass(ClassName.FADE + " " + ClassName.SHOW);
}; // Private
_proto._getContent = function _getContent() {
return this.element.getAttribute('data-content') || this.config.content;
};
_proto._cleanTipClass = function _cleanTipClass() {
var $tip = $$$1(this.getTipElement());
var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);
if (tabClass !== null && tabClass.length > 0) {
$tip.removeClass(tabClass.join(''));
}
}; // Static
Popover._jQueryInterface = function _jQueryInterface(config) {
return this.each(function () {
var data = $$$1(this).data(DATA_KEY);
var _config = typeof config === 'object' ? config : null;
if (!data && /destroy|hide/.test(config)) {
return;
}
if (!data) {
data = new Popover(this, _config);
$$$1(this).data(DATA_KEY, data);
}
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError("No method named \"" + config + "\"");
}
data[config]();
}
});
};
_createClass(Popover, null, [{
key: "VERSION",
// Getters
get: function get() {
return VERSION;
}
}, {
key: "Default",
get: function get() {
return Default;
}
}, {
key: "NAME",
get: function get() {
return NAME;
}
}, {
key: "DATA_KEY",
get: function get() {
return DATA_KEY;
}
}, {
key: "Event",
get: function get() {
return Event;
}
}, {
key: "EVENT_KEY",
get: function get() {
return EVENT_KEY;
}
}, {
key: "DefaultType",
get: function get() {
return DefaultType;
}
}]);
return Popover;
}(Tooltip);
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = Popover._jQueryInterface;
$$$1.fn[NAME].Constructor = Popover;
$$$1.fn[NAME].noConflict = function () {
$$$1.fn[NAME] = JQUERY_NO_CONFLICT;
return Popover._jQueryInterface;
};
return Popover;
}($);
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0): scrollspy.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var ScrollSpy = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'scrollspy';
var VERSION = '4.0.0';
var DATA_KEY = 'bs.scrollspy';
var EVENT_KEY = "." + DATA_KEY;
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var Default = {
offset: 10,
method: 'auto',
target: ''
};
var DefaultType = {
offset: 'number',
method: 'string',
target: '(string|element)'
};
var Event = {
ACTIVATE: "activate" + EVENT_KEY,
SCROLL: "scroll" + EVENT_KEY,
LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY
};
var ClassName = {
DROPDOWN_ITEM: 'dropdown-item',
DROPDOWN_MENU: 'dropdown-menu',
ACTIVE: 'active'
};
var Selector = {
DATA_SPY: '[data-spy="scroll"]',
ACTIVE: '.active',
NAV_LIST_GROUP: '.nav, .list-group',
NAV_LINKS: '.nav-link',
NAV_ITEMS: '.nav-item',
LIST_ITEMS: '.list-group-item',
DROPDOWN: '.dropdown',
DROPDOWN_ITEMS: '.dropdown-item',
DROPDOWN_TOGGLE: '.dropdown-toggle'
};
var OffsetMethod = {
OFFSET: 'offset',
POSITION: 'position'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var ScrollSpy =
/*#__PURE__*/
function () {
function ScrollSpy(element, config) {
var _this = this;
this._element = element;
this._scrollElement = element.tagName === 'BODY' ? window : element;
this._config = this._getConfig(config);
this._selector = this._config.target + " " + Selector.NAV_LINKS + "," + (this._config.target + " " + Selector.LIST_ITEMS + ",") + (this._config.target + " " + Selector.DROPDOWN_ITEMS);
this._offsets = [];
this._targets = [];
this._activeTarget = null;
this._scrollHeight = 0;
$$$1(this._scrollElement).on(Event.SCROLL, function (event) {
return _this._process(event);
});
this.refresh();
this._process();
} // Getters
var _proto = ScrollSpy.prototype;
// Public
_proto.refresh = function refresh() {
var _this2 = this;
var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION;
var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;
this._offsets = [];
this._targets = [];
this._scrollHeight = this._getScrollHeight();
var targets = $$$1.makeArray($$$1(this._selector));
targets.map(function (element) {
var target;
var targetSelector = Util.getSelectorFromElement(element);
if (targetSelector) {
target = $$$1(targetSelector)[0];
}
if (target) {
var targetBCR = target.getBoundingClientRect();
if (targetBCR.width || targetBCR.height) {
// TODO (fat): remove sketch reliance on jQuery position/offset
return [$$$1(target)[offsetMethod]().top + offsetBase, targetSelector];
}
}
return null;
}).filter(function (item) {
return item;
}).sort(function (a, b) {
return a[0] - b[0];
}).forEach(function (item) {
_this2._offsets.push(item[0]);
_this2._targets.push(item[1]);
});
};
_proto.dispose = function dispose() {
$$$1.removeData(this._element, DATA_KEY);
$$$1(this._scrollElement).off(EVENT_KEY);
this._element = null;
this._scrollElement = null;
this._config = null;
this._selector = null;
this._offsets = null;
this._targets = null;
this._activeTarget = null;
this._scrollHeight = null;
}; // Private
_proto._getConfig = function _getConfig(config) {
config = _extends({}, Default, config);
if (typeof config.target !== 'string') {
var id = $$$1(config.target).attr('id');
if (!id) {
id = Util.getUID(NAME);
$$$1(config.target).attr('id', id);
}
config.target = "#" + id;
}
Util.typeCheckConfig(NAME, config, DefaultType);
return config;
};
_proto._getScrollTop = function _getScrollTop() {
return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;
};
_proto._getScrollHeight = function _getScrollHeight() {
return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
};
_proto._getOffsetHeight = function _getOffsetHeight() {
return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;
};
_proto._process = function _process() {
var scrollTop = this._getScrollTop() + this._config.offset;
var scrollHeight = this._getScrollHeight();
var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();
if (this._scrollHeight !== scrollHeight) {
this.refresh();
}
if (scrollTop >= maxScroll) {
var target = this._targets[this._targets.length - 1];
if (this._activeTarget !== target) {
this._activate(target);
}
return;
}
if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
this._activeTarget = null;
this._clear();
return;
}
for (var i = this._offsets.length; i--;) {
var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);
if (isActiveTarget) {
this._activate(this._targets[i]);
}
}
};
_proto._activate = function _activate(target) {
this._activeTarget = target;
this._clear();
var queries = this._selector.split(','); // eslint-disable-next-line arrow-body-style
queries = queries.map(function (selector) {
return selector + "[data-target=\"" + target + "\"]," + (selector + "[href=\"" + target + "\"]");
});
var $link = $$$1(queries.join(','));
if ($link.hasClass(ClassName.DROPDOWN_ITEM)) {
$link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE);
$link.addClass(ClassName.ACTIVE);
} else {
// Set triggered link as active
$link.addClass(ClassName.ACTIVE); // Set triggered links parents as active
// With both and markup a parent is the previous sibling of any nav ancestor
$link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_LINKS + ", " + Selector.LIST_ITEMS).addClass(ClassName.ACTIVE); // Handle special case when .nav-link is inside .nav-item
$link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_ITEMS).children(Selector.NAV_LINKS).addClass(ClassName.ACTIVE);
}
$$$1(this._scrollElement).trigger(Event.ACTIVATE, {
relatedTarget: target
});
};
_proto._clear = function _clear() {
$$$1(this._selector).filter(Selector.ACTIVE).removeClass(ClassName.ACTIVE);
}; // Static
ScrollSpy._jQueryInterface = function _jQueryInterface(config) {
return this.each(function () {
var data = $$$1(this).data(DATA_KEY);
var _config = typeof config === 'object' && config;
if (!data) {
data = new ScrollSpy(this, _config);
$$$1(this).data(DATA_KEY, data);
}
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError("No method named \"" + config + "\"");
}
data[config]();
}
});
};
_createClass(ScrollSpy, null, [{
key: "VERSION",
get: function get() {
return VERSION;
}
}, {
key: "Default",
get: function get() {
return Default;
}
}]);
return ScrollSpy;
}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
$$$1(window).on(Event.LOAD_DATA_API, function () {
var scrollSpys = $$$1.makeArray($$$1(Selector.DATA_SPY));
for (var i = scrollSpys.length; i--;) {
var $spy = $$$1(scrollSpys[i]);
ScrollSpy._jQueryInterface.call($spy, $spy.data());
}
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = ScrollSpy._jQueryInterface;
$$$1.fn[NAME].Constructor = ScrollSpy;
$$$1.fn[NAME].noConflict = function () {
$$$1.fn[NAME] = JQUERY_NO_CONFLICT;
return ScrollSpy._jQueryInterface;
};
return ScrollSpy;
}($);
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0): tab.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var Tab = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'tab';
var VERSION = '4.0.0';
var DATA_KEY = 'bs.tab';
var EVENT_KEY = "." + DATA_KEY;
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var TRANSITION_DURATION = 150;
var Event = {
HIDE: "hide" + EVENT_KEY,
HIDDEN: "hidden" + EVENT_KEY,
SHOW: "show" + EVENT_KEY,
SHOWN: "shown" + EVENT_KEY,
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
};
var ClassName = {
DROPDOWN_MENU: 'dropdown-menu',
ACTIVE: 'active',
DISABLED: 'disabled',
FADE: 'fade',
SHOW: 'show'
};
var Selector = {
DROPDOWN: '.dropdown',
NAV_LIST_GROUP: '.nav, .list-group',
ACTIVE: '.active',
ACTIVE_UL: '> li > .active',
DATA_TOGGLE: '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',
DROPDOWN_TOGGLE: '.dropdown-toggle',
DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var Tab =
/*#__PURE__*/
function () {
function Tab(element) {
this._element = element;
} // Getters
var _proto = Tab.prototype;
// Public
_proto.show = function show() {
var _this = this;
if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && $$$1(this._element).hasClass(ClassName.ACTIVE) || $$$1(this._element).hasClass(ClassName.DISABLED)) {
return;
}
var target;
var previous;
var listElement = $$$1(this._element).closest(Selector.NAV_LIST_GROUP)[0];
var selector = Util.getSelectorFromElement(this._element);
if (listElement) {
var itemSelector = listElement.nodeName === 'UL' ? Selector.ACTIVE_UL : Selector.ACTIVE;
previous = $$$1.makeArray($$$1(listElement).find(itemSelector));
previous = previous[previous.length - 1];
}
var hideEvent = $$$1.Event(Event.HIDE, {
relatedTarget: this._element
});
var showEvent = $$$1.Event(Event.SHOW, {
relatedTarget: previous
});
if (previous) {
$$$1(previous).trigger(hideEvent);
}
$$$1(this._element).trigger(showEvent);
if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) {
return;
}
if (selector) {
target = $$$1(selector)[0];
}
this._activate(this._element, listElement);
var complete = function complete() {
var hiddenEvent = $$$1.Event(Event.HIDDEN, {
relatedTarget: _this._element
});
var shownEvent = $$$1.Event(Event.SHOWN, {
relatedTarget: previous
});
$$$1(previous).trigger(hiddenEvent);
$$$1(_this._element).trigger(shownEvent);
};
if (target) {
this._activate(target, target.parentNode, complete);
} else {
complete();
}
};
_proto.dispose = function dispose() {
$$$1.removeData(this._element, DATA_KEY);
this._element = null;
}; // Private
_proto._activate = function _activate(element, container, callback) {
var _this2 = this;
var activeElements;
if (container.nodeName === 'UL') {
activeElements = $$$1(container).find(Selector.ACTIVE_UL);
} else {
activeElements = $$$1(container).children(Selector.ACTIVE);
}
var active = activeElements[0];
var isTransitioning = callback && Util.supportsTransitionEnd() && active && $$$1(active).hasClass(ClassName.FADE);
var complete = function complete() {
return _this2._transitionComplete(element, active, callback);
};
if (active && isTransitioning) {
$$$1(active).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
} else {
complete();
}
};
_proto._transitionComplete = function _transitionComplete(element, active, callback) {
if (active) {
$$$1(active).removeClass(ClassName.SHOW + " " + ClassName.ACTIVE);
var dropdownChild = $$$1(active.parentNode).find(Selector.DROPDOWN_ACTIVE_CHILD)[0];
if (dropdownChild) {
$$$1(dropdownChild).removeClass(ClassName.ACTIVE);
}
if (active.getAttribute('role') === 'tab') {
active.setAttribute('aria-selected', false);
}
}
$$$1(element).addClass(ClassName.ACTIVE);
if (element.getAttribute('role') === 'tab') {
element.setAttribute('aria-selected', true);
}
Util.reflow(element);
$$$1(element).addClass(ClassName.SHOW);
if (element.parentNode && $$$1(element.parentNode).hasClass(ClassName.DROPDOWN_MENU)) {
var dropdownElement = $$$1(element).closest(Selector.DROPDOWN)[0];
if (dropdownElement) {
$$$1(dropdownElement).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE);
}
element.setAttribute('aria-expanded', true);
}
if (callback) {
callback();
}
}; // Static
Tab._jQueryInterface = function _jQueryInterface(config) {
return this.each(function () {
var $this = $$$1(this);
var data = $this.data(DATA_KEY);
if (!data) {
data = new Tab(this);
$this.data(DATA_KEY, data);
}
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError("No method named \"" + config + "\"");
}
data[config]();
}
});
};
_createClass(Tab, null, [{
key: "VERSION",
get: function get() {
return VERSION;
}
}]);
return Tab;
}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
$$$1(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
event.preventDefault();
Tab._jQueryInterface.call($$$1(this), 'show');
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = Tab._jQueryInterface;
$$$1.fn[NAME].Constructor = Tab;
$$$1.fn[NAME].noConflict = function () {
$$$1.fn[NAME] = JQUERY_NO_CONFLICT;
return Tab._jQueryInterface;
};
return Tab;
}($);
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): index.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
(function ($$$1) {
if (typeof $$$1 === 'undefined') {
throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.');
}
var version = $$$1.fn.jquery.split(' ')[0].split('.');
var minMajor = 1;
var ltMajor = 2;
var minMinor = 9;
var minPatch = 1;
var maxMajor = 4;
if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {
throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0');
}
})($);
exports.Util = Util;
exports.Alert = Alert;
exports.Button = Button;
exports.Carousel = Carousel;
exports.Collapse = Collapse;
exports.Dropdown = Dropdown;
exports.Modal = Modal;
exports.Popover = Popover;
exports.Scrollspy = ScrollSpy;
exports.Tab = Tab;
exports.Tooltip = Tooltip;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=bootstrap.js.map
================================================
FILE: assets/libraries/phpseclib/Crypt/AES.php
================================================
* setKey('abcdefghijklmnop');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $aes->decrypt($aes->encrypt($plaintext));
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_AES
* @author Jim Wigginton
* @copyright 2008 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_Rijndael
*/
if (!class_exists('Crypt_Rijndael')) {
include_once 'Rijndael.php';
}
/**#@+
* @access public
* @see self::encrypt()
* @see self::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
*/
define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB);
/**
* Encrypt / decrypt using the Code Book Chaining mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
*/
define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**
* Pure-PHP implementation of AES.
*
* @package Crypt_AES
* @author Jim Wigginton
* @access public
*/
class Crypt_AES extends Crypt_Rijndael
{
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'AES';
/**
* Dummy function
*
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
*
* @see Crypt_Rijndael::setBlockLength()
* @access public
* @param int $length
*/
function setBlockLength($length)
{
return;
}
/**
* Sets the key length
*
* Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
*
* @see Crypt_Rijndael:setKeyLength()
* @access public
* @param int $length
*/
function setKeyLength($length)
{
switch ($length) {
case 160:
$length = 192;
break;
case 224:
$length = 256;
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Rijndael supports five different key lengths, AES only supports three.
*
* @see Crypt_Rijndael:setKey()
* @see setKeyLength()
* @access public
* @param string $key
*/
function setKey($key)
{
parent::setKey($key);
if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_length = 16;
break;
case $length <= 24:
$this->key_length = 24;
break;
default:
$this->key_length = 32;
}
$this->_setEngine();
}
}
}
================================================
FILE: assets/libraries/phpseclib/Crypt/Base.php
================================================
* @author Hans-Juergen Petrich
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**#@+
* @access public
* @see self::encrypt()
* @see self::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_MODE_CTR', -1);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
*/
define('CRYPT_MODE_ECB', 1);
/**
* Encrypt / decrypt using the Code Book Chaining mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_MODE_CBC', 2);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
define('CRYPT_MODE_CFB', 3);
/**
* Encrypt / decrypt using the Output Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
*/
define('CRYPT_MODE_OFB', 4);
/**
* Encrypt / decrypt using streaming mode.
*/
define('CRYPT_MODE_STREAM', 5);
/**#@-*/
/**#@+
* @access private
* @see self::Crypt_Base()
* @internal These constants are for internal use only
*/
/**
* Base value for the internal implementation $engine switch
*/
define('CRYPT_ENGINE_INTERNAL', 1);
/**
* Base value for the mcrypt implementation $engine switch
*/
define('CRYPT_ENGINE_MCRYPT', 2);
/**
* Base value for the OpenSSL implementation $engine switch
*/
define('CRYPT_ENGINE_OPENSSL', 3);
/**#@-*/
/**
* Base Class for all Crypt_* cipher classes
*
* @package Crypt_Base
* @author Jim Wigginton
* @author Hans-Juergen Petrich
* @access public
*/
class Crypt_Base
{
/**
* The Encryption Mode
*
* @see self::Crypt_Base()
* @var int
* @access private
*/
var $mode;
/**
* The Block Length of the block cipher
*
* @var int
* @access private
*/
var $block_size = 16;
/**
* The Key
*
* @see self::setKey()
* @var string
* @access private
*/
var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
/**
* The Initialization Vector
*
* @see self::setIV()
* @var string
* @access private
*/
var $iv;
/**
* A "sliding" Initialization Vector
*
* @see self::enableContinuousBuffer()
* @see self::_clearBuffers()
* @var string
* @access private
*/
var $encryptIV;
/**
* A "sliding" Initialization Vector
*
* @see self::enableContinuousBuffer()
* @see self::_clearBuffers()
* @var string
* @access private
*/
var $decryptIV;
/**
* Continuous Buffer status
*
* @see self::enableContinuousBuffer()
* @var bool
* @access private
*/
var $continuousBuffer = false;
/**
* Encryption buffer for CTR, OFB and CFB modes
*
* @see self::encrypt()
* @see self::_clearBuffers()
* @var array
* @access private
*/
var $enbuffer;
/**
* Decryption buffer for CTR, OFB and CFB modes
*
* @see self::decrypt()
* @see self::_clearBuffers()
* @var array
* @access private
*/
var $debuffer;
/**
* mcrypt resource for encryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see self::encrypt()
* @var resource
* @access private
*/
var $enmcrypt;
/**
* mcrypt resource for decryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see self::decrypt()
* @var resource
* @access private
*/
var $demcrypt;
/**
* Does the enmcrypt resource need to be (re)initialized?
*
* @see Crypt_Twofish::setKey()
* @see Crypt_Twofish::setIV()
* @var bool
* @access private
*/
var $enchanged = true;
/**
* Does the demcrypt resource need to be (re)initialized?
*
* @see Crypt_Twofish::setKey()
* @see Crypt_Twofish::setIV()
* @var bool
* @access private
*/
var $dechanged = true;
/**
* mcrypt resource for CFB mode
*
* mcrypt's CFB mode, in (and only in) buffered context,
* is broken, so phpseclib implements the CFB mode by it self,
* even when the mcrypt php extension is available.
*
* In order to do the CFB-mode work (fast) phpseclib
* use a separate ECB-mode mcrypt resource.
*
* @link http://phpseclib.sourceforge.net/cfb-demo.phps
* @see self::encrypt()
* @see self::decrypt()
* @see self::_setupMcrypt()
* @var resource
* @access private
*/
var $ecb;
/**
* Optimizing value while CFB-encrypting
*
* Only relevant if $continuousBuffer enabled
* and $engine == CRYPT_ENGINE_MCRYPT
*
* It's faster to re-init $enmcrypt if
* $buffer bytes > $cfb_init_len than
* using the $ecb resource furthermore.
*
* This value depends of the chosen cipher
* and the time it would be needed for it's
* initialization [by mcrypt_generic_init()]
* which, typically, depends on the complexity
* on its internaly Key-expanding algorithm.
*
* @see self::encrypt()
* @var int
* @access private
*/
var $cfb_init_len = 600;
/**
* Does internal cipher state need to be (re)initialized?
*
* @see self::setKey()
* @see self::setIV()
* @see self::disableContinuousBuffer()
* @var bool
* @access private
*/
var $changed = true;
/**
* Padding status
*
* @see self::enablePadding()
* @var bool
* @access private
*/
var $padding = true;
/**
* Is the mode one that is paddable?
*
* @see self::Crypt_Base()
* @var bool
* @access private
*/
var $paddable = false;
/**
* Holds which crypt engine internaly should be use,
* which will be determined automatically on __construct()
*
* Currently available $engines are:
* - CRYPT_ENGINE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required)
* - CRYPT_ENGINE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
* - CRYPT_ENGINE_INTERNAL (slower, pure php-engine, no php-extension required)
*
* @see self::_setEngine()
* @see self::encrypt()
* @see self::decrypt()
* @var int
* @access private
*/
var $engine;
/**
* Holds the preferred crypt engine
*
* @see self::_setEngine()
* @see self::setPreferredEngine()
* @var int
* @access private
*/
var $preferredEngine;
/**
* The mcrypt specific name of the cipher
*
* Only used if $engine == CRYPT_ENGINE_MCRYPT
*
* @link http://www.php.net/mcrypt_module_open
* @link http://www.php.net/mcrypt_list_algorithms
* @see self::_setupMcrypt()
* @var string
* @access private
*/
var $cipher_name_mcrypt;
/**
* The openssl specific name of the cipher
*
* Only used if $engine == CRYPT_ENGINE_OPENSSL
*
* @link http://www.php.net/openssl-get-cipher-methods
* @var string
* @access private
*/
var $cipher_name_openssl;
/**
* The openssl specific name of the cipher in ECB mode
*
* If OpenSSL does not support the mode we're trying to use (CTR)
* it can still be emulated with ECB mode.
*
* @link http://www.php.net/openssl-get-cipher-methods
* @var string
* @access private
*/
var $cipher_name_openssl_ecb;
/**
* The default salt used by setPassword()
*
* @see self::setPassword()
* @var string
* @access private
*/
var $password_default_salt = 'phpseclib/salt';
/**
* The namespace used by the cipher for its constants.
*
* ie: AES.php is using CRYPT_AES_MODE_* for its constants
* so $const_namespace is AES
*
* DES.php is using CRYPT_DES_MODE_* for its constants
* so $const_namespace is DES... and so on
*
* All CRYPT_<$const_namespace>_MODE_* are aliases of
* the generic CRYPT_MODE_* constants, so both could be used
* for each cipher.
*
* Example:
* $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode
* $aes = new Crypt_AES(CRYPT_MODE_CFB); // identical
*
* @see self::Crypt_Base()
* @var string
* @access private
*/
var $const_namespace;
/**
* The name of the performance-optimized callback function
*
* Used by encrypt() / decrypt()
* only if $engine == CRYPT_ENGINE_INTERNAL
*
* @see self::encrypt()
* @see self::decrypt()
* @see self::_setupInlineCrypt()
* @see self::$use_inline_crypt
* @var Callback
* @access private
*/
var $inline_crypt;
/**
* Holds whether performance-optimized $inline_crypt() can/should be used.
*
* @see self::encrypt()
* @see self::decrypt()
* @see self::inline_crypt
* @var mixed
* @access private
*/
var $use_inline_crypt;
/**
* If OpenSSL can be used in ECB but not in CTR we can emulate CTR
*
* @see self::_openssl_ctr_process()
* @var bool
* @access private
*/
var $openssl_emulate_ctr = false;
/**
* Determines what options are passed to openssl_encrypt/decrypt
*
* @see self::isValidEngine()
* @var mixed
* @access private
*/
var $openssl_options;
/**
* Has the key length explicitly been set or should it be derived from the key, itself?
*
* @see self::setKeyLength()
* @var bool
* @access private
*/
var $explicit_key_length = false;
/**
* Don't truncate / null pad key
*
* @see self::_clearBuffers()
* @var bool
* @access private
*/
var $skip_key_adjustment = false;
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
*
* - CRYPT_MODE_ECB
*
* - CRYPT_MODE_CBC
*
* - CRYPT_MODE_CTR
*
* - CRYPT_MODE_CFB
*
* - CRYPT_MODE_OFB
*
* (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...)
*
* If not explicitly set, CRYPT_MODE_CBC will be used.
*
* @param int $mode
* @access public
*/
function __construct($mode = CRYPT_MODE_CBC)
{
// $mode dependent settings
switch ($mode) {
case CRYPT_MODE_ECB:
$this->paddable = true;
$this->mode = CRYPT_MODE_ECB;
break;
case CRYPT_MODE_CTR:
case CRYPT_MODE_CFB:
case CRYPT_MODE_OFB:
case CRYPT_MODE_STREAM:
$this->mode = $mode;
break;
case CRYPT_MODE_CBC:
default:
$this->paddable = true;
$this->mode = CRYPT_MODE_CBC;
}
$this->_setEngine();
// Determining whether inline crypting can be used by the cipher
if ($this->use_inline_crypt !== false) {
$this->use_inline_crypt = version_compare(PHP_VERSION, '5.3.0') >= 0 || function_exists('create_function');
}
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param int $mode
* @access public
*/
function Crypt_Base($mode = CRYPT_MODE_CBC)
{
$this->__construct($mode);
}
/**
* Sets the initialization vector. (optional)
*
* SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explicitly set, it'll be assumed
* to be all zero's.
*
* @access public
* @param string $iv
* @internal Can be overwritten by a sub class, but does not have to be
*/
function setIV($iv)
{
if ($this->mode == CRYPT_MODE_ECB) {
return;
}
$this->iv = $iv;
$this->changed = true;
}
/**
* Sets the key length.
*
* Keys with explicitly set lengths need to be treated accordingly
*
* @access public
* @param int $length
*/
function setKeyLength($length)
{
$this->explicit_key_length = true;
$this->changed = true;
$this->_setEngine();
}
/**
* Returns the current key length in bits
*
* @access public
* @return int
*/
function getKeyLength()
{
return $this->key_length << 3;
}
/**
* Returns the current block length in bits
*
* @access public
* @return int
*/
function getBlockLength()
{
return $this->block_size << 3;
}
/**
* Sets the key.
*
* The min/max length(s) of the key depends on the cipher which is used.
* If the key not fits the length(s) of the cipher it will paded with null bytes
* up to the closest valid key length. If the key is more than max length,
* we trim the excess bits.
*
* If the key is not explicitly set, it'll be assumed to be all null bytes.
*
* @access public
* @param string $key
* @internal Could, but not must, extend by the child Crypt_* class
*/
function setKey($key)
{
if (!$this->explicit_key_length) {
$this->setKeyLength(strlen($key) << 3);
$this->explicit_key_length = false;
}
$this->key = $key;
$this->changed = true;
$this->_setEngine();
}
/**
* Sets the password.
*
* Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
* {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
* $hash, $salt, $count, $dkLen
*
* Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
*
* @see Crypt/Hash.php
* @param string $password
* @param string $method
* @return bool
* @access public
* @internal Could, but not must, extend by the child Crypt_* class
*/
function setPassword($password, $method = 'pbkdf2')
{
$key = '';
switch ($method) {
default: // 'pbkdf2' or 'pbkdf1'
$func_args = func_get_args();
// Hash function
$hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
// WPA and WPA2 use the SSID as the salt
$salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
// RFC2898#section-4.2 uses 1,000 iterations by default
// WPA and WPA2 use 4,096.
$count = isset($func_args[4]) ? $func_args[4] : 1000;
// Keylength
if (isset($func_args[5]) && $func_args[5] > 0) {
$dkLen = $func_args[5];
} else {
$dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
}
switch (true) {
case $method == 'pbkdf1':
if (!class_exists('Crypt_Hash')) {
include_once 'Crypt/Hash.php';
}
$hashObj = new Crypt_Hash();
$hashObj->setHash($hash);
if ($dkLen > $hashObj->getLength()) {
user_error('Derived key too long');
return false;
}
$t = $password . $salt;
for ($i = 0; $i < $count; ++$i) {
$t = $hashObj->hash($t);
}
$key = substr($t, 0, $dkLen);
$this->setKey(substr($key, 0, $dkLen >> 1));
$this->setIV(substr($key, $dkLen >> 1));
return true;
// Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
case !function_exists('hash_pbkdf2'):
case !function_exists('hash_algos'):
case !in_array($hash, hash_algos()):
if (!class_exists('Crypt_Hash')) {
include_once 'Crypt/Hash.php';
}
$i = 1;
$hmac = new Crypt_Hash();
$hmac->setHash($hash);
$hmac->setKey($password);
while (strlen($key) < $dkLen) {
$f = $u = $hmac->hash($salt . pack('N', $i++));
for ($j = 2; $j <= $count; ++$j) {
$u = $hmac->hash($u);
$f^= $u;
}
$key.= $f;
}
$key = substr($key, 0, $dkLen);
break;
default:
$key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
}
}
$this->setKey($key);
return true;
}
/**
* Encrypts a message.
*
* $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
* implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
* necessary are discussed in the following
* URL:
*
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
*
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
* strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
* length.
*
* @see self::decrypt()
* @access public
* @param string $plaintext
* @return string $ciphertext
* @internal Could, but not must, extend by the child Crypt_* class
*/
function encrypt($plaintext)
{
if ($this->paddable) {
$plaintext = $this->_pad($plaintext);
}
if ($this->engine === CRYPT_ENGINE_OPENSSL) {
if ($this->changed) {
$this->_clearBuffers();
$this->changed = false;
}
switch ($this->mode) {
case CRYPT_MODE_STREAM:
return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
case CRYPT_MODE_ECB:
$result = @openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
case CRYPT_MODE_CBC:
$result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
if (!defined('OPENSSL_RAW_DATA')) {
$result = substr($result, 0, -$this->block_size);
}
if ($this->continuousBuffer) {
$this->encryptIV = substr($result, -$this->block_size);
}
return $result;
case CRYPT_MODE_CTR:
return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
case CRYPT_MODE_CFB:
// cfb loosely routines inspired by openssl's:
// {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
$ciphertext = '';
if ($this->continuousBuffer) {
$iv = &$this->encryptIV;
$pos = &$this->enbuffer['pos'];
} else {
$iv = $this->encryptIV;
$pos = 0;
}
$len = strlen($plaintext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $this->block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
$plaintext = substr($plaintext, $i);
}
$overflow = $len % $this->block_size;
if ($overflow) {
$ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
$iv = $this->_string_pop($ciphertext, $this->block_size);
$size = $len - $overflow;
$block = $iv ^ substr($plaintext, -$overflow);
$iv = substr_replace($iv, $block, 0, $overflow);
$ciphertext.= $block;
$pos = $overflow;
} elseif ($len) {
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
$iv = substr($ciphertext, -$this->block_size);
}
return $ciphertext;
case CRYPT_MODE_OFB:
return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
}
}
if ($this->engine === CRYPT_ENGINE_MCRYPT) {
if ($this->changed) {
$this->_setupMcrypt();
$this->changed = false;
}
if ($this->enchanged) {
@mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
$this->enchanged = false;
}
// re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
// using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
// rewritten CFB implementation the above outputs the same thing twice.
if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
$block_size = $this->block_size;
$iv = &$this->encryptIV;
$pos = &$this->enbuffer['pos'];
$len = strlen($plaintext);
$ciphertext = '';
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
$this->enbuffer['enmcrypt_init'] = true;
}
if ($len >= $block_size) {
if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
if ($this->enbuffer['enmcrypt_init'] === true) {
@mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
$this->enbuffer['enmcrypt_init'] = false;
}
$ciphertext.= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
$iv = substr($ciphertext, -$block_size);
$len%= $block_size;
} else {
while ($len >= $block_size) {
$iv = @mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
$ciphertext.= $iv;
$len-= $block_size;
$i+= $block_size;
}
}
}
if ($len) {
$iv = @mcrypt_generic($this->ecb, $iv);
$block = $iv ^ substr($plaintext, -$len);
$iv = substr_replace($iv, $block, 0, $len);
$ciphertext.= $block;
$pos = $len;
}
return $ciphertext;
}
$ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext);
if (!$this->continuousBuffer) {
@mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
}
return $ciphertext;
}
if ($this->changed) {
$this->_setup();
$this->changed = false;
}
if ($this->use_inline_crypt) {
$inline = $this->inline_crypt;
return $inline('encrypt', $this, $plaintext);
}
$buffer = &$this->enbuffer;
$block_size = $this->block_size;
$ciphertext = '';
switch ($this->mode) {
case CRYPT_MODE_ECB:
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
}
break;
case CRYPT_MODE_CBC:
$xor = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
$block = $this->_encryptBlock($block ^ $xor);
$xor = $block;
$ciphertext.= $block;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
}
break;
case CRYPT_MODE_CTR:
$xor = $this->encryptIV;
if (strlen($buffer['ciphertext'])) {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
if (strlen($block) > strlen($buffer['ciphertext'])) {
$buffer['ciphertext'].= $this->_encryptBlock($xor);
}
$this->_increment_str($xor);
$key = $this->_string_shift($buffer['ciphertext'], $block_size);
$ciphertext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
$key = $this->_encryptBlock($xor);
$this->_increment_str($xor);
$ciphertext.= $block ^ $key;
}
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
if ($start = strlen($plaintext) % $block_size) {
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
}
}
break;
case CRYPT_MODE_CFB:
// cfb loosely routines inspired by openssl's:
// {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
if ($this->continuousBuffer) {
$iv = &$this->encryptIV;
$pos = &$buffer['pos'];
} else {
$iv = $this->encryptIV;
$pos = 0;
}
$len = strlen($plaintext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
}
while ($len >= $block_size) {
$iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
$ciphertext.= $iv;
$len-= $block_size;
$i+= $block_size;
}
if ($len) {
$iv = $this->_encryptBlock($iv);
$block = $iv ^ substr($plaintext, $i);
$iv = substr_replace($iv, $block, 0, $len);
$ciphertext.= $block;
$pos = $len;
}
break;
case CRYPT_MODE_OFB:
$xor = $this->encryptIV;
if (strlen($buffer['xor'])) {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
if (strlen($block) > strlen($buffer['xor'])) {
$xor = $this->_encryptBlock($xor);
$buffer['xor'].= $xor;
}
$key = $this->_string_shift($buffer['xor'], $block_size);
$ciphertext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$xor = $this->_encryptBlock($xor);
$ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
if ($start = strlen($plaintext) % $block_size) {
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
}
}
break;
case CRYPT_MODE_STREAM:
$ciphertext = $this->_encryptBlock($plaintext);
break;
}
return $ciphertext;
}
/**
* Decrypts a message.
*
* If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
* it is.
*
* @see self::encrypt()
* @access public
* @param string $ciphertext
* @return string $plaintext
* @internal Could, but not must, extend by the child Crypt_* class
*/
function decrypt($ciphertext)
{
if ($this->paddable) {
// we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}:
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
$ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
}
if ($this->engine === CRYPT_ENGINE_OPENSSL) {
if ($this->changed) {
$this->_clearBuffers();
$this->changed = false;
}
switch ($this->mode) {
case CRYPT_MODE_STREAM:
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
break;
case CRYPT_MODE_ECB:
if (!defined('OPENSSL_RAW_DATA')) {
$ciphertext.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
}
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
break;
case CRYPT_MODE_CBC:
if (!defined('OPENSSL_RAW_DATA')) {
$padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
$ciphertext.= substr(@openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
$offset = 2 * $this->block_size;
} else {
$offset = $this->block_size;
}
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
if ($this->continuousBuffer) {
$this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
}
break;
case CRYPT_MODE_CTR:
$plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
break;
case CRYPT_MODE_CFB:
// cfb loosely routines inspired by openssl's:
// {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
$plaintext = '';
if ($this->continuousBuffer) {
$iv = &$this->decryptIV;
$pos = &$this->buffer['pos'];
} else {
$iv = $this->decryptIV;
$pos = 0;
}
$len = strlen($ciphertext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $this->block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
$ciphertext = substr($ciphertext, $i);
}
$overflow = $len % $this->block_size;
if ($overflow) {
$plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
if ($len - $overflow) {
$iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
}
$iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
$plaintext.= $iv ^ substr($ciphertext, -$overflow);
$iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
$pos = $overflow;
} elseif ($len) {
$plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $iv);
$iv = substr($ciphertext, -$this->block_size);
}
break;
case CRYPT_MODE_OFB:
$plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
}
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}
if ($this->engine === CRYPT_ENGINE_MCRYPT) {
$block_size = $this->block_size;
if ($this->changed) {
$this->_setupMcrypt();
$this->changed = false;
}
if ($this->dechanged) {
@mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
$this->dechanged = false;
}
if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
$iv = &$this->decryptIV;
$pos = &$this->debuffer['pos'];
$len = strlen($ciphertext);
$plaintext = '';
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
}
if ($len >= $block_size) {
$cb = substr($ciphertext, $i, $len - $len % $block_size);
$plaintext.= @mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
$iv = substr($cb, -$block_size);
$len%= $block_size;
}
if ($len) {
$iv = @mcrypt_generic($this->ecb, $iv);
$plaintext.= $iv ^ substr($ciphertext, -$len);
$iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
$pos = $len;
}
return $plaintext;
}
$plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext);
if (!$this->continuousBuffer) {
@mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
}
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}
if ($this->changed) {
$this->_setup();
$this->changed = false;
}
if ($this->use_inline_crypt) {
$inline = $this->inline_crypt;
return $inline('decrypt', $this, $ciphertext);
}
$block_size = $this->block_size;
$buffer = &$this->debuffer;
$plaintext = '';
switch ($this->mode) {
case CRYPT_MODE_ECB:
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
}
break;
case CRYPT_MODE_CBC:
$xor = $this->decryptIV;
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
$plaintext.= $this->_decryptBlock($block) ^ $xor;
$xor = $block;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
}
break;
case CRYPT_MODE_CTR:
$xor = $this->decryptIV;
if (strlen($buffer['ciphertext'])) {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
if (strlen($block) > strlen($buffer['ciphertext'])) {
$buffer['ciphertext'].= $this->_encryptBlock($xor);
$this->_increment_str($xor);
}
$key = $this->_string_shift($buffer['ciphertext'], $block_size);
$plaintext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
$key = $this->_encryptBlock($xor);
$this->_increment_str($xor);
$plaintext.= $block ^ $key;
}
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
if ($start = strlen($ciphertext) % $block_size) {
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
}
}
break;
case CRYPT_MODE_CFB:
if ($this->continuousBuffer) {
$iv = &$this->decryptIV;
$pos = &$buffer['pos'];
} else {
$iv = $this->decryptIV;
$pos = 0;
}
$len = strlen($ciphertext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len-= $max;
$pos = 0;
} else {
$i = $len;
$pos+= $len;
$len = 0;
}
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
}
while ($len >= $block_size) {
$iv = $this->_encryptBlock($iv);
$cb = substr($ciphertext, $i, $block_size);
$plaintext.= $iv ^ $cb;
$iv = $cb;
$len-= $block_size;
$i+= $block_size;
}
if ($len) {
$iv = $this->_encryptBlock($iv);
$plaintext.= $iv ^ substr($ciphertext, $i);
$iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
$pos = $len;
}
break;
case CRYPT_MODE_OFB:
$xor = $this->decryptIV;
if (strlen($buffer['xor'])) {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
if (strlen($block) > strlen($buffer['xor'])) {
$xor = $this->_encryptBlock($xor);
$buffer['xor'].= $xor;
}
$key = $this->_string_shift($buffer['xor'], $block_size);
$plaintext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$xor = $this->_encryptBlock($xor);
$plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
if ($start = strlen($ciphertext) % $block_size) {
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
}
}
break;
case CRYPT_MODE_STREAM:
$plaintext = $this->_decryptBlock($ciphertext);
break;
}
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}
/**
* OpenSSL CTR Processor
*
* PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
* for CTR is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
* and Crypt_Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
* function will emulate CTR with ECB when necessary.
*
* @see self::encrypt()
* @see self::decrypt()
* @param string $plaintext
* @param string $encryptIV
* @param array $buffer
* @return string
* @access private
*/
function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
{
$ciphertext = '';
$block_size = $this->block_size;
$key = $this->key;
if ($this->openssl_emulate_ctr) {
$xor = $encryptIV;
if (strlen($buffer['ciphertext'])) {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
if (strlen($block) > strlen($buffer['ciphertext'])) {
$result = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
$result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
$buffer['ciphertext'].= $result;
}
$this->_increment_str($xor);
$otp = $this->_string_shift($buffer['ciphertext'], $block_size);
$ciphertext.= $block ^ $otp;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
$otp = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
$otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
$this->_increment_str($xor);
$ciphertext.= $block ^ $otp;
}
}
if ($this->continuousBuffer) {
$encryptIV = $xor;
if ($start = strlen($plaintext) % $block_size) {
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
}
}
return $ciphertext;
}
if (strlen($buffer['ciphertext'])) {
$ciphertext = $plaintext ^ $this->_string_shift($buffer['ciphertext'], strlen($plaintext));
$plaintext = substr($plaintext, strlen($ciphertext));
if (!strlen($plaintext)) {
return $ciphertext;
}
}
$overflow = strlen($plaintext) % $block_size;
if ($overflow) {
$plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
$encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
$temp = $this->_string_pop($encrypted, $block_size);
$ciphertext.= $encrypted . ($plaintext2 ^ $temp);
if ($this->continuousBuffer) {
$buffer['ciphertext'] = substr($temp, $overflow);
$encryptIV = $temp;
}
} elseif (!strlen($buffer['ciphertext'])) {
$ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
$temp = $this->_string_pop($ciphertext, $block_size);
if ($this->continuousBuffer) {
$encryptIV = $temp;
}
}
if ($this->continuousBuffer) {
if (!defined('OPENSSL_RAW_DATA')) {
$encryptIV.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
}
$encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
if ($overflow) {
$this->_increment_str($encryptIV);
}
}
return $ciphertext;
}
/**
* OpenSSL OFB Processor
*
* PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
* for OFB is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
* and Crypt_Base::decrypt().
*
* @see self::encrypt()
* @see self::decrypt()
* @param string $plaintext
* @param string $encryptIV
* @param array $buffer
* @return string
* @access private
*/
function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
{
if (strlen($buffer['xor'])) {
$ciphertext = $plaintext ^ $buffer['xor'];
$buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
$plaintext = substr($plaintext, strlen($ciphertext));
} else {
$ciphertext = '';
}
$block_size = $this->block_size;
$len = strlen($plaintext);
$key = $this->key;
$overflow = $len % $block_size;
if (strlen($plaintext)) {
if ($overflow) {
$ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
$xor = $this->_string_pop($ciphertext, $block_size);
if ($this->continuousBuffer) {
$encryptIV = $xor;
}
$ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow);
if ($this->continuousBuffer) {
$buffer['xor'] = $xor;
}
} else {
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
if ($this->continuousBuffer) {
$encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
}
}
}
return $ciphertext;
}
/**
* phpseclib <-> OpenSSL Mode Mapper
*
* May need to be overwritten by classes extending this one in some cases
*
* @return int
* @access private
*/
function _openssl_translate_mode()
{
switch ($this->mode) {
case CRYPT_MODE_ECB:
return 'ecb';
case CRYPT_MODE_CBC:
return 'cbc';
case CRYPT_MODE_CTR:
return 'ctr';
case CRYPT_MODE_CFB:
return 'cfb';
case CRYPT_MODE_OFB:
return 'ofb';
}
}
/**
* Pad "packets".
*
* Block ciphers working by encrypting between their specified [$this->]block_size at a time
* If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
* pad the input so that it is of the proper length.
*
* Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
* where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
* away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
* transmitted separately)
*
* @see self::disablePadding()
* @access public
*/
function enablePadding()
{
$this->padding = true;
}
/**
* Do not pad packets.
*
* @see self::enablePadding()
* @access public
*/
function disablePadding()
{
$this->padding = false;
}
/**
* Treat consecutive "packets" as if they are a continuous buffer.
*
* Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
* will yield different outputs:
*
*
* echo $rijndael->encrypt(substr($plaintext, 0, 16));
* echo $rijndael->encrypt(substr($plaintext, 16, 16));
*
*
* echo $rijndael->encrypt($plaintext);
*
*
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
* another, as demonstrated with the following:
*
*
* $rijndael->encrypt(substr($plaintext, 0, 16));
* echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
*
*
* echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
*
*
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
*
* Put another way, when the continuous buffer is enabled, the state of the Crypt_*() object changes after each
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
* however, they are also less intuitive and more likely to cause you problems.
*
* @see self::disableContinuousBuffer()
* @access public
* @internal Could, but not must, extend by the child Crypt_* class
*/
function enableContinuousBuffer()
{
if ($this->mode == CRYPT_MODE_ECB) {
return;
}
$this->continuousBuffer = true;
$this->_setEngine();
}
/**
* Treat consecutive packets as if they are a discontinuous buffer.
*
* The default behavior.
*
* @see self::enableContinuousBuffer()
* @access public
* @internal Could, but not must, extend by the child Crypt_* class
*/
function disableContinuousBuffer()
{
if ($this->mode == CRYPT_MODE_ECB) {
return;
}
if (!$this->continuousBuffer) {
return;
}
$this->continuousBuffer = false;
$this->changed = true;
$this->_setEngine();
}
/**
* Test for engine validity
*
* @see self::Crypt_Base()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
switch ($engine) {
case CRYPT_ENGINE_OPENSSL:
if ($this->mode == CRYPT_MODE_STREAM && $this->continuousBuffer) {
return false;
}
$this->openssl_emulate_ctr = false;
$result = $this->cipher_name_openssl &&
extension_loaded('openssl') &&
// PHP 5.3.0 - 5.3.2 did not let you set IV's
version_compare(PHP_VERSION, '5.3.3', '>=');
if (!$result) {
return false;
}
// prior to PHP 5.4.0 OPENSSL_RAW_DATA and OPENSSL_ZERO_PADDING were not defined. instead of expecting an integer
// $options openssl_encrypt expected a boolean $raw_data.
if (!defined('OPENSSL_RAW_DATA')) {
$this->openssl_options = true;
} else {
$this->openssl_options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
}
$methods = openssl_get_cipher_methods();
if (in_array($this->cipher_name_openssl, $methods)) {
return true;
}
// not all of openssl's symmetric cipher's support ctr. for those
// that don't we'll emulate it
switch ($this->mode) {
case CRYPT_MODE_CTR:
if (in_array($this->cipher_name_openssl_ecb, $methods)) {
$this->openssl_emulate_ctr = true;
return true;
}
}
return false;
case CRYPT_ENGINE_MCRYPT:
return $this->cipher_name_mcrypt &&
extension_loaded('mcrypt') &&
in_array($this->cipher_name_mcrypt, @mcrypt_list_algorithms());
case CRYPT_ENGINE_INTERNAL:
return true;
}
return false;
}
/**
* Sets the preferred crypt engine
*
* Currently, $engine could be:
*
* - CRYPT_ENGINE_OPENSSL [very fast]
*
* - CRYPT_ENGINE_MCRYPT [fast]
*
* - CRYPT_ENGINE_INTERNAL [slow]
*
* If the preferred crypt engine is not available the fastest available one will be used
*
* @see self::Crypt_Base()
* @param int $engine
* @access public
*/
function setPreferredEngine($engine)
{
switch ($engine) {
//case CRYPT_ENGINE_OPENSSL:
case CRYPT_ENGINE_MCRYPT:
case CRYPT_ENGINE_INTERNAL:
$this->preferredEngine = $engine;
break;
default:
$this->preferredEngine = CRYPT_ENGINE_OPENSSL;
}
$this->_setEngine();
}
/**
* Returns the engine currently being utilized
*
* @see self::_setEngine()
* @access public
*/
function getEngine()
{
return $this->engine;
}
/**
* Sets the engine as appropriate
*
* @see self::Crypt_Base()
* @access private
*/
function _setEngine()
{
$this->engine = null;
$candidateEngines = array(
$this->preferredEngine,
CRYPT_ENGINE_OPENSSL,
CRYPT_ENGINE_MCRYPT
);
foreach ($candidateEngines as $engine) {
if ($this->isValidEngine($engine)) {
$this->engine = $engine;
break;
}
}
if (!$this->engine) {
$this->engine = CRYPT_ENGINE_INTERNAL;
}
if ($this->engine != CRYPT_ENGINE_MCRYPT && $this->enmcrypt) {
// Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
// (re)open them with the module named in $this->cipher_name_mcrypt
@mcrypt_module_close($this->enmcrypt);
@mcrypt_module_close($this->demcrypt);
$this->enmcrypt = null;
$this->demcrypt = null;
if ($this->ecb) {
@mcrypt_module_close($this->ecb);
$this->ecb = null;
}
}
$this->changed = true;
}
/**
* Encrypts a block
*
* @access private
* @param string $in
* @return string
* @internal Must be extended by the child Crypt_* class
*/
function _encryptBlock($in)
{
user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
}
/**
* Decrypts a block
*
* @access private
* @param string $in
* @return string
* @internal Must be extended by the child Crypt_* class
*/
function _decryptBlock($in)
{
user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
}
/**
* Setup the key (expansion)
*
* Only used if $engine == CRYPT_ENGINE_INTERNAL
*
* @see self::_setup()
* @access private
* @internal Must be extended by the child Crypt_* class
*/
function _setupKey()
{
user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
}
/**
* Setup the CRYPT_ENGINE_INTERNAL $engine
*
* (re)init, if necessary, the internal cipher $engine and flush all $buffers
* Used (only) if $engine == CRYPT_ENGINE_INTERNAL
*
* _setup() will be called each time if $changed === true
* typically this happens when using one or more of following public methods:
*
* - setKey()
*
* - setIV()
*
* - disableContinuousBuffer()
*
* - First run of encrypt() / decrypt() with no init-settings
*
* @see self::setKey()
* @see self::setIV()
* @see self::disableContinuousBuffer()
* @access private
* @internal _setup() is always called before en/decryption.
* @internal Could, but not must, extend by the child Crypt_* class
*/
function _setup()
{
$this->_clearBuffers();
$this->_setupKey();
if ($this->use_inline_crypt) {
$this->_setupInlineCrypt();
}
}
/**
* Setup the CRYPT_ENGINE_MCRYPT $engine
*
* (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
* Used (only) if $engine = CRYPT_ENGINE_MCRYPT
*
* _setupMcrypt() will be called each time if $changed === true
* typically this happens when using one or more of following public methods:
*
* - setKey()
*
* - setIV()
*
* - disableContinuousBuffer()
*
* - First run of encrypt() / decrypt()
*
* @see self::setKey()
* @see self::setIV()
* @see self::disableContinuousBuffer()
* @access private
* @internal Could, but not must, extend by the child Crypt_* class
*/
function _setupMcrypt()
{
$this->_clearBuffers();
$this->enchanged = $this->dechanged = true;
if (!isset($this->enmcrypt)) {
static $mcrypt_modes = array(
CRYPT_MODE_CTR => 'ctr',
CRYPT_MODE_ECB => MCRYPT_MODE_ECB,
CRYPT_MODE_CBC => MCRYPT_MODE_CBC,
CRYPT_MODE_CFB => 'ncfb',
CRYPT_MODE_OFB => MCRYPT_MODE_NOFB,
CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM,
);
$this->demcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
$this->enmcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
// we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
// to workaround mcrypt's broken ncfb implementation in buffered mode
// see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
if ($this->mode == CRYPT_MODE_CFB) {
$this->ecb = @mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
}
} // else should mcrypt_generic_deinit be called?
if ($this->mode == CRYPT_MODE_CFB) {
@mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
}
}
/**
* Pads a string
*
* Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
* $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
* chr($this->block_size - (strlen($text) % $this->block_size)
*
* If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
* and padding will, hence forth, be enabled.
*
* @see self::_unpad()
* @param string $text
* @access private
* @return string
*/
function _pad($text)
{
$length = strlen($text);
if (!$this->padding) {
if ($length % $this->block_size == 0) {
return $text;
} else {
user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
$this->padding = true;
}
}
$pad = $this->block_size - ($length % $this->block_size);
return str_pad($text, $length + $pad, chr($pad));
}
/**
* Unpads a string.
*
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
* and false will be returned.
*
* @see self::_pad()
* @param string $text
* @access private
* @return string
*/
function _unpad($text)
{
if (!$this->padding) {
return $text;
}
$length = ord($text[strlen($text) - 1]);
if (!$length || $length > $this->block_size) {
return false;
}
return substr($text, 0, -$length);
}
/**
* Clears internal buffers
*
* Clearing/resetting the internal buffers is done everytime
* after disableContinuousBuffer() or on cipher $engine (re)init
* ie after setKey() or setIV()
*
* @access public
* @internal Could, but not must, extend by the child Crypt_* class
*/
function _clearBuffers()
{
$this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
// mcrypt's handling of invalid's $iv:
// $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
$this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
if (!$this->skip_key_adjustment) {
$this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
}
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @access private
* @return string
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
/**
* String Pop
*
* Inspired by array_pop
*
* @param string $string
* @param int $index
* @access private
* @return string
*/
function _string_pop(&$string, $index = 1)
{
$substr = substr($string, -$index);
$string = substr($string, 0, -$index);
return $substr;
}
/**
* Increment the current string
*
* @see self::decrypt()
* @see self::encrypt()
* @param string $var
* @access private
*/
function _increment_str(&$var)
{
for ($i = 4; $i <= strlen($var); $i+= 4) {
$temp = substr($var, -$i, 4);
switch ($temp) {
case "\xFF\xFF\xFF\xFF":
$var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
break;
case "\x7F\xFF\xFF\xFF":
$var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
return;
default:
$temp = unpack('Nnum', $temp);
$var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
return;
}
}
$remainder = strlen($var) % 4;
if ($remainder == 0) {
return;
}
$temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT));
$temp = substr(pack('N', $temp['num'] + 1), -$remainder);
$var = substr_replace($var, $temp, 0, $remainder);
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* Stores the created (or existing) callback function-name
* in $this->inline_crypt
*
* Internally for phpseclib developers:
*
* _setupInlineCrypt() would be called only if:
*
* - $engine == CRYPT_ENGINE_INTERNAL and
*
* - $use_inline_crypt === true
*
* - each time on _setup(), after(!) _setupKey()
*
*
* This ensures that _setupInlineCrypt() has always a
* full ready2go initializated internal cipher $engine state
* where, for example, the keys allready expanded,
* keys/block_size calculated and such.
*
* It is, each time if called, the responsibility of _setupInlineCrypt():
*
* - to set $this->inline_crypt to a valid and fully working callback function
* as a (faster) replacement for encrypt() / decrypt()
*
* - NOT to create unlimited callback functions (for memory reasons!)
* no matter how often _setupInlineCrypt() would be called. At some
* point of amount they must be generic re-useable.
*
* - the code of _setupInlineCrypt() it self,
* and the generated callback code,
* must be, in following order:
* - 100% safe
* - 100% compatible to encrypt()/decrypt()
* - using only php5+ features/lang-constructs/php-extensions if
* compatibility (down to php4) or fallback is provided
* - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
* - >= 10% faster than encrypt()/decrypt() [which is, by the way,
* the reason for the existence of _setupInlineCrypt() :-)]
* - memory-nice
* - short (as good as possible)
*
* Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
* - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class.
* - The following variable names are reserved:
* - $_* (all variable names prefixed with an underscore)
* - $self (object reference to it self. Do not use $this, but $self instead)
* - $in (the content of $in has to en/decrypt by the generated code)
* - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
*
*
* @see self::_setup()
* @see self::_createInlineCryptFunction()
* @see self::encrypt()
* @see self::decrypt()
* @access private
* @internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()
*/
function _setupInlineCrypt()
{
// If, for any reason, an extending Crypt_Base() Crypt_* class
// not using inline crypting then it must be ensured that: $this->use_inline_crypt = false
// ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class,
// in the constructor at object instance-time
// or, if it's runtime-specific, at runtime
$this->use_inline_crypt = false;
}
/**
* Creates the performance-optimized function for en/decrypt()
*
* Internally for phpseclib developers:
*
* _createInlineCryptFunction():
*
* - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
* with the current [$this->]mode of operation code
*
* - create the $inline function, which called by encrypt() / decrypt()
* as its replacement to speed up the en/decryption operations.
*
* - return the name of the created $inline callback function
*
* - used to speed up en/decryption
*
*
*
* The main reason why can speed up things [up to 50%] this way are:
*
* - using variables more effective then regular.
* (ie no use of expensive arrays but integers $k_0, $k_1 ...
* or even, for example, the pure $key[] values hardcoded)
*
* - avoiding 1000's of function calls of ie _encryptBlock()
* but inlining the crypt operations.
* in the mode of operation for() loop.
*
* - full loop unroll the (sometimes key-dependent) rounds
* avoiding this way ++$i counters and runtime-if's etc...
*
* The basic code architectur of the generated $inline en/decrypt()
* lambda function, in pseudo php, is:
*
*
* +----------------------------------------------------------------------------------------------+
* | callback $inline = create_function: |
* | lambda_function_0001_crypt_ECB($action, $text) |
* | { |
* | INSERT PHP CODE OF: |
* | $cipher_code['init_crypt']; // general init code. |
* | // ie: $sbox'es declarations used for |
* | // encrypt and decrypt'ing. |
* | |
* | switch ($action) { |
* | case 'encrypt': |
* | INSERT PHP CODE OF: |
* | $cipher_code['init_encrypt']; // encrypt sepcific init code. |
* | ie: specified $key or $box |
* | declarations for encrypt'ing. |
* | |
* | foreach ($ciphertext) { |
* | $in = $block_size of $ciphertext; |
* | |
* | INSERT PHP CODE OF: |
* | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: |
* | // strlen($in) == $this->block_size |
* | // here comes the cipher algorithm in action |
* | // for encryption. |
* | // $cipher_code['encrypt_block'] has to |
* | // encrypt the content of the $in variable |
* | |
* | $plaintext .= $in; |
* | } |
* | return $plaintext; |
* | |
* | case 'decrypt': |
* | INSERT PHP CODE OF: |
* | $cipher_code['init_decrypt']; // decrypt sepcific init code |
* | ie: specified $key or $box |
* | declarations for decrypt'ing. |
* | foreach ($plaintext) { |
* | $in = $block_size of $plaintext; |
* | |
* | INSERT PHP CODE OF: |
* | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always |
* | // strlen($in) == $this->block_size |
* | // here comes the cipher algorithm in action |
* | // for decryption. |
* | // $cipher_code['decrypt_block'] has to |
* | // decrypt the content of the $in variable |
* | $ciphertext .= $in; |
* | } |
* | return $ciphertext; |
* | } |
* | } |
* +----------------------------------------------------------------------------------------------+
*
*
* See also the Crypt_*::_setupInlineCrypt()'s for
* productive inline $cipher_code's how they works.
*
* Structure of:
*
* $cipher_code = array(
* 'init_crypt' => (string) '', // optional
* 'init_encrypt' => (string) '', // optional
* 'init_decrypt' => (string) '', // optional
* 'encrypt_block' => (string) '', // required
* 'decrypt_block' => (string) '' // required
* );
*
*
* @see self::_setupInlineCrypt()
* @see self::encrypt()
* @see self::decrypt()
* @param array $cipher_code
* @access private
* @return string (the name of the created callback function)
*/
function _createInlineCryptFunction($cipher_code)
{
$block_size = $this->block_size;
// optional
$init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : '';
$init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : '';
$init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : '';
// required
$encrypt_block = $cipher_code['encrypt_block'];
$decrypt_block = $cipher_code['decrypt_block'];
// Generating mode of operation inline code,
// merged with the $cipher_code algorithm
// for encrypt- and decryption.
switch ($this->mode) {
case CRYPT_MODE_ECB:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_plaintext_len = strlen($_text);
for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
$in = substr($_text, $_i, '.$block_size.');
'.$encrypt_block.'
$_ciphertext.= $in;
}
return $_ciphertext;
';
$decrypt = $init_decrypt . '
$_plaintext = "";
$_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
$_ciphertext_len = strlen($_text);
for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
$in = substr($_text, $_i, '.$block_size.');
'.$decrypt_block.'
$_plaintext.= $in;
}
return $self->_unpad($_plaintext);
';
break;
case CRYPT_MODE_CTR:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_plaintext_len = strlen($_text);
$_xor = $self->encryptIV;
$_buffer = &$self->enbuffer;
if (strlen($_buffer["ciphertext"])) {
for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
$_block = substr($_text, $_i, '.$block_size.');
if (strlen($_block) > strlen($_buffer["ciphertext"])) {
$in = $_xor;
'.$encrypt_block.'
$self->_increment_str($_xor);
$_buffer["ciphertext"].= $in;
}
$_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
$_ciphertext.= $_block ^ $_key;
}
} else {
for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
$_block = substr($_text, $_i, '.$block_size.');
$in = $_xor;
'.$encrypt_block.'
$self->_increment_str($_xor);
$_key = $in;
$_ciphertext.= $_block ^ $_key;
}
}
if ($self->continuousBuffer) {
$self->encryptIV = $_xor;
if ($_start = $_plaintext_len % '.$block_size.') {
$_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
}
}
return $_ciphertext;
';
$decrypt = $init_encrypt . '
$_plaintext = "";
$_ciphertext_len = strlen($_text);
$_xor = $self->decryptIV;
$_buffer = &$self->debuffer;
if (strlen($_buffer["ciphertext"])) {
for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
$_block = substr($_text, $_i, '.$block_size.');
if (strlen($_block) > strlen($_buffer["ciphertext"])) {
$in = $_xor;
'.$encrypt_block.'
$self->_increment_str($_xor);
$_buffer["ciphertext"].= $in;
}
$_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
$_plaintext.= $_block ^ $_key;
}
} else {
for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
$_block = substr($_text, $_i, '.$block_size.');
$in = $_xor;
'.$encrypt_block.'
$self->_increment_str($_xor);
$_key = $in;
$_plaintext.= $_block ^ $_key;
}
}
if ($self->continuousBuffer) {
$self->decryptIV = $_xor;
if ($_start = $_ciphertext_len % '.$block_size.') {
$_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
}
}
return $_plaintext;
';
break;
case CRYPT_MODE_CFB:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_buffer = &$self->enbuffer;
if ($self->continuousBuffer) {
$_iv = &$self->encryptIV;
$_pos = &$_buffer["pos"];
} else {
$_iv = $self->encryptIV;
$_pos = 0;
}
$_len = strlen($_text);
$_i = 0;
if ($_pos) {
$_orig_pos = $_pos;
$_max = '.$block_size.' - $_pos;
if ($_len >= $_max) {
$_i = $_max;
$_len-= $_max;
$_pos = 0;
} else {
$_i = $_len;
$_pos+= $_len;
$_len = 0;
}
$_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
$_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
}
while ($_len >= '.$block_size.') {
$in = $_iv;
'.$encrypt_block.';
$_iv = $in ^ substr($_text, $_i, '.$block_size.');
$_ciphertext.= $_iv;
$_len-= '.$block_size.';
$_i+= '.$block_size.';
}
if ($_len) {
$in = $_iv;
'.$encrypt_block.'
$_iv = $in;
$_block = $_iv ^ substr($_text, $_i);
$_iv = substr_replace($_iv, $_block, 0, $_len);
$_ciphertext.= $_block;
$_pos = $_len;
}
return $_ciphertext;
';
$decrypt = $init_encrypt . '
$_plaintext = "";
$_buffer = &$self->debuffer;
if ($self->continuousBuffer) {
$_iv = &$self->decryptIV;
$_pos = &$_buffer["pos"];
} else {
$_iv = $self->decryptIV;
$_pos = 0;
}
$_len = strlen($_text);
$_i = 0;
if ($_pos) {
$_orig_pos = $_pos;
$_max = '.$block_size.' - $_pos;
if ($_len >= $_max) {
$_i = $_max;
$_len-= $_max;
$_pos = 0;
} else {
$_i = $_len;
$_pos+= $_len;
$_len = 0;
}
$_plaintext = substr($_iv, $_orig_pos) ^ $_text;
$_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
}
while ($_len >= '.$block_size.') {
$in = $_iv;
'.$encrypt_block.'
$_iv = $in;
$cb = substr($_text, $_i, '.$block_size.');
$_plaintext.= $_iv ^ $cb;
$_iv = $cb;
$_len-= '.$block_size.';
$_i+= '.$block_size.';
}
if ($_len) {
$in = $_iv;
'.$encrypt_block.'
$_iv = $in;
$_plaintext.= $_iv ^ substr($_text, $_i);
$_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
$_pos = $_len;
}
return $_plaintext;
';
break;
case CRYPT_MODE_OFB:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_plaintext_len = strlen($_text);
$_xor = $self->encryptIV;
$_buffer = &$self->enbuffer;
if (strlen($_buffer["xor"])) {
for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
$_block = substr($_text, $_i, '.$block_size.');
if (strlen($_block) > strlen($_buffer["xor"])) {
$in = $_xor;
'.$encrypt_block.'
$_xor = $in;
$_buffer["xor"].= $_xor;
}
$_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
$_ciphertext.= $_block ^ $_key;
}
} else {
for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
$in = $_xor;
'.$encrypt_block.'
$_xor = $in;
$_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
}
$_key = $_xor;
}
if ($self->continuousBuffer) {
$self->encryptIV = $_xor;
if ($_start = $_plaintext_len % '.$block_size.') {
$_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
}
}
return $_ciphertext;
';
$decrypt = $init_encrypt . '
$_plaintext = "";
$_ciphertext_len = strlen($_text);
$_xor = $self->decryptIV;
$_buffer = &$self->debuffer;
if (strlen($_buffer["xor"])) {
for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
$_block = substr($_text, $_i, '.$block_size.');
if (strlen($_block) > strlen($_buffer["xor"])) {
$in = $_xor;
'.$encrypt_block.'
$_xor = $in;
$_buffer["xor"].= $_xor;
}
$_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
$_plaintext.= $_block ^ $_key;
}
} else {
for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
$in = $_xor;
'.$encrypt_block.'
$_xor = $in;
$_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
}
$_key = $_xor;
}
if ($self->continuousBuffer) {
$self->decryptIV = $_xor;
if ($_start = $_ciphertext_len % '.$block_size.') {
$_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
}
}
return $_plaintext;
';
break;
case CRYPT_MODE_STREAM:
$encrypt = $init_encrypt . '
$_ciphertext = "";
'.$encrypt_block.'
return $_ciphertext;
';
$decrypt = $init_decrypt . '
$_plaintext = "";
'.$decrypt_block.'
return $_plaintext;
';
break;
// case CRYPT_MODE_CBC:
default:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_plaintext_len = strlen($_text);
$in = $self->encryptIV;
for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
$in = substr($_text, $_i, '.$block_size.') ^ $in;
'.$encrypt_block.'
$_ciphertext.= $in;
}
if ($self->continuousBuffer) {
$self->encryptIV = $in;
}
return $_ciphertext;
';
$decrypt = $init_decrypt . '
$_plaintext = "";
$_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
$_ciphertext_len = strlen($_text);
$_iv = $self->decryptIV;
for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
$in = $_block = substr($_text, $_i, '.$block_size.');
'.$decrypt_block.'
$_plaintext.= $in ^ $_iv;
$_iv = $_block;
}
if ($self->continuousBuffer) {
$self->decryptIV = $_iv;
}
return $self->_unpad($_plaintext);
';
break;
}
// Create the $inline function and return its name as string. Ready to run!
if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
eval('$func = function ($_action, &$self, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' } };');
return $func;
}
return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
}
/**
* Holds the lambda_functions table (classwide)
*
* Each name of the lambda function, created from
* _setupInlineCrypt() && _createInlineCryptFunction()
* is stored, classwide (!), here for reusing.
*
* The string-based index of $function is a classwide
* unique value representing, at least, the $mode of
* operation (or more... depends of the optimizing level)
* for which $mode the lambda function was created.
*
* @access private
* @return array &$functions
*/
function &_getLambdaFunctions()
{
static $functions = array();
return $functions;
}
/**
* Generates a digest from $bytes
*
* @see self::_setupInlineCrypt()
* @access private
* @param $bytes
* @return string
*/
function _hashInlineCryptFunction($bytes)
{
if (!defined('CRYPT_BASE_WHIRLPOOL_AVAILABLE')) {
define('CRYPT_BASE_WHIRLPOOL_AVAILABLE', (bool)(extension_loaded('hash') && in_array('whirlpool', hash_algos())));
}
$result = '';
$hash = $bytes;
switch (true) {
case CRYPT_BASE_WHIRLPOOL_AVAILABLE:
foreach (str_split($bytes, 64) as $t) {
$hash = hash('whirlpool', $hash, true);
$result .= $t ^ $hash;
}
return $result . hash('whirlpool', $hash, true);
default:
$len = strlen($bytes);
for ($i = 0; $i < $len; $i+=20) {
$t = substr($bytes, $i, 20);
$hash = pack('H*', sha1($hash));
$result .= $t ^ $hash;
}
return $result . pack('H*', sha1($hash));
}
}
/**
* Convert float to int
*
* On 32-bit Linux installs running PHP < 5.3 converting floats to ints doesn't always work
*
* @access private
* @param string $x
* @return int
*/
function safe_intval($x)
{
switch (true) {
case is_int($x):
// PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
case version_compare(PHP_VERSION, '5.3.0') >= 0 && (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
// PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
return $x;
}
return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
((fmod(floor($x / 0x80000000), 2) & 1) << 31);
}
/**
* eval()'able string for in-line float to int
*
* @access private
* @return string
*/
function safe_intval_inline()
{
// on 32-bit linux systems with PHP < 5.3 float to integer conversion is bad
switch (true) {
case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
case version_compare(PHP_VERSION, '5.3.0') >= 0 && (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
return '%s';
break;
default:
$safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
}
}
}
================================================
FILE: assets/libraries/phpseclib/Crypt/Blowfish.php
================================================
* setKey('12345678901234567890123456789012');
*
* $plaintext = str_repeat('a', 1024);
*
* echo $blowfish->decrypt($blowfish->encrypt($plaintext));
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_Blowfish
* @author Jim Wigginton
* @author Hans-Juergen Petrich
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_Base
*
* Base cipher class
*/
if (!class_exists('Crypt_Base')) {
include_once 'Base.php';
}
/**#@+
* @access public
* @see self::encrypt()
* @see self::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_BLOWFISH_MODE_CTR', CRYPT_MODE_CTR);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
*/
define('CRYPT_BLOWFISH_MODE_ECB', CRYPT_MODE_ECB);
/**
* Encrypt / decrypt using the Code Book Chaining mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_BLOWFISH_MODE_CBC', CRYPT_MODE_CBC);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
define('CRYPT_BLOWFISH_MODE_CFB', CRYPT_MODE_CFB);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
*/
define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**
* Pure-PHP implementation of Blowfish.
*
* @package Crypt_Blowfish
* @author Jim Wigginton
* @author Hans-Juergen Petrich
* @access public
*/
class Crypt_Blowfish extends Crypt_Base
{
/**
* Block Length of the cipher
*
* @see Crypt_Base::block_size
* @var int
* @access private
*/
var $block_size = 8;
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'BLOWFISH';
/**
* The mcrypt specific name of the cipher
*
* @see Crypt_Base::cipher_name_mcrypt
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'blowfish';
/**
* Optimizing value while CFB-encrypting
*
* @see Crypt_Base::cfb_init_len
* @var int
* @access private
*/
var $cfb_init_len = 500;
/**
* The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
*
* S-Box 0
*
* @access private
* @var array
*/
var $sbox0 = array(
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
);
/**
* S-Box 1
*
* @access private
* @var array
*/
var $sbox1 = array(
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
);
/**
* S-Box 2
*
* @access private
* @var array
*/
var $sbox2 = array(
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
);
/**
* S-Box 3
*
* @access private
* @var array
*/
var $sbox3 = array(
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
);
/**
* P-Array consists of 18 32-bit subkeys
*
* @var array
* @access private
*/
var $parray = array(
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
);
/**
* The BCTX-working Array
*
* Holds the expanded key [p] and the key-depended s-boxes [sb]
*
* @var array
* @access private
*/
var $bctx;
/**
* Holds the last used key
*
* @var array
* @access private
*/
var $kl;
/**
* The Key Length (in bytes)
*
* @see Crypt_Base::setKeyLength()
* @var int
* @access private
* @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
* because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
* derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
* of that, we'll just precompute it once.
*/
var $key_length = 16;
/**
* Sets the key length.
*
* Key lengths can be between 32 and 448 bits.
*
* @access public
* @param int $length
*/
function setKeyLength($length)
{
if ($length < 32) {
$this->key_length = 4;
} elseif ($length > 448) {
$this->key_length = 56;
} else {
$this->key_length = $length >> 3;
}
parent::setKeyLength($length);
}
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::isValidEngine()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
if ($engine == CRYPT_ENGINE_OPENSSL) {
if (version_compare(PHP_VERSION, '5.3.7') < 0 && $this->key_length != 16) {
return false;
}
if ($this->key_length < 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'bf-ecb';
$this->cipher_name_openssl = 'bf-' . $this->_openssl_translate_mode();
}
return parent::isValidEngine($engine);
}
/**
* Setup the key (expansion)
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
// already expanded
return;
}
$this->kl = array('key' => $this->key);
/* key-expanding p[] and S-Box building sb[] */
$this->bctx = array(
'p' => array(),
'sb' => array(
$this->sbox0,
$this->sbox1,
$this->sbox2,
$this->sbox3
)
);
// unpack binary string in unsigned chars
$key = array_values(unpack('C*', $this->key));
$keyl = count($key);
for ($j = 0, $i = 0; $i < 18; ++$i) {
// xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
for ($data = 0, $k = 0; $k < 4; ++$k) {
$data = ($data << 8) | $key[$j];
if (++$j >= $keyl) {
$j = 0;
}
}
$this->bctx['p'][] = $this->parray[$i] ^ $data;
}
// encrypt the zero-string, replace P1 and P2 with the encrypted data,
// encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
$data = "\0\0\0\0\0\0\0\0";
for ($i = 0; $i < 18; $i += 2) {
list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
$this->bctx['p'][$i ] = $l;
$this->bctx['p'][$i + 1] = $r;
}
for ($i = 0; $i < 4; ++$i) {
for ($j = 0; $j < 256; $j += 2) {
list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
$this->bctx['sb'][$i][$j ] = $l;
$this->bctx['sb'][$i][$j + 1] = $r;
}
}
}
/**
* Encrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _encryptBlock($in)
{
$p = $this->bctx["p"];
// extract($this->bctx["sb"], EXTR_PREFIX_ALL, "sb"); // slower
$sb_0 = $this->bctx["sb"][0];
$sb_1 = $this->bctx["sb"][1];
$sb_2 = $this->bctx["sb"][2];
$sb_3 = $this->bctx["sb"][3];
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
for ($i = 0; $i < 16; $i+= 2) {
$l^= $p[$i];
$r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]);
$r^= $p[$i + 1];
$l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]);
}
return pack("N*", $r ^ $p[17], $l ^ $p[16]);
}
/**
* Decrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _decryptBlock($in)
{
$p = $this->bctx["p"];
$sb_0 = $this->bctx["sb"][0];
$sb_1 = $this->bctx["sb"][1];
$sb_2 = $this->bctx["sb"][2];
$sb_3 = $this->bctx["sb"][3];
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
for ($i = 17; $i > 2; $i-= 2) {
$l^= $p[$i];
$r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]);
$r^= $p[$i - 1];
$l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]);
}
return pack("N*", $r ^ $p[0], $l ^ $p[1]);
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* @see Crypt_Base::_setupInlineCrypt()
* @access private
*/
function _setupInlineCrypt()
{
$lambda_functions =& Crypt_Blowfish::_getLambdaFunctions();
// We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
// (Currently, for Crypt_Blowfish, one generated $lambda_function cost on php5.5@32bit ~100kb unfreeable mem and ~180kb on php5.5@64bit)
// After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
$gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
// Generation of a unique hash for our generated code
$code_hash = "Crypt_Blowfish, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
$safeint = $this->safe_intval_inline();
if (!isset($lambda_functions[$code_hash])) {
switch (true) {
case $gen_hi_opt_code:
$p = $this->bctx['p'];
$init_crypt = '
static $sb_0, $sb_1, $sb_2, $sb_3;
if (!$sb_0) {
$sb_0 = $self->bctx["sb"][0];
$sb_1 = $self->bctx["sb"][1];
$sb_2 = $self->bctx["sb"][2];
$sb_3 = $self->bctx["sb"][3];
}
';
break;
default:
$p = array();
for ($i = 0; $i < 18; ++$i) {
$p[] = '$p_' . $i;
}
$init_crypt = '
list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"];
list(' . implode(',', $p) . ') = $self->bctx["p"];
';
}
// Generating encrypt code:
$encrypt_block = '
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
';
for ($i = 0; $i < 16; $i+= 2) {
$encrypt_block.= '
$l^= ' . $p[$i] . ';
$r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]') . ';
$r^= ' . $p[$i + 1] . ';
$l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]') . ';
';
}
$encrypt_block.= '
$in = pack("N*",
$r ^ ' . $p[17] . ',
$l ^ ' . $p[16] . '
);
';
// Generating decrypt code:
$decrypt_block = '
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
';
for ($i = 17; $i > 2; $i-= 2) {
$decrypt_block.= '
$l^= ' . $p[$i] . ';
$r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
$sb_2[$l >> 8 & 0xff]) +
$sb_3[$l & 0xff]') . ';
$r^= ' . $p[$i - 1] . ';
$l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
$sb_2[$r >> 8 & 0xff]) +
$sb_3[$r & 0xff]') . ';
';
}
$decrypt_block.= '
$in = pack("N*",
$r ^ ' . $p[0] . ',
$l ^ ' . $p[1] . '
);
';
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => $init_crypt,
'init_encrypt' => '',
'init_decrypt' => '',
'encrypt_block' => $encrypt_block,
'decrypt_block' => $decrypt_block
)
);
}
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
================================================
FILE: assets/libraries/phpseclib/Crypt/DES.php
================================================
* setKey('abcdefgh');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $des->decrypt($des->encrypt($plaintext));
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_DES
* @author Jim Wigginton
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_Base
*
* Base cipher class
*/
if (!class_exists('Crypt_Base')) {
include_once 'Base.php';
}
/**#@+
* @access private
* @see self::_setupKey()
* @see self::_processBlock()
*/
/**
* Contains $keys[CRYPT_DES_ENCRYPT]
*/
define('CRYPT_DES_ENCRYPT', 0);
/**
* Contains $keys[CRYPT_DES_DECRYPT]
*/
define('CRYPT_DES_DECRYPT', 1);
/**#@-*/
/**#@+
* @access public
* @see self::encrypt()
* @see self::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_DES_MODE_CTR', CRYPT_MODE_CTR);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
*/
define('CRYPT_DES_MODE_ECB', CRYPT_MODE_ECB);
/**
* Encrypt / decrypt using the Code Book Chaining mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_DES_MODE_CBC', CRYPT_MODE_CBC);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
define('CRYPT_DES_MODE_CFB', CRYPT_MODE_CFB);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
*/
define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**
* Pure-PHP implementation of DES.
*
* @package Crypt_DES
* @author Jim Wigginton
* @access public
*/
class Crypt_DES extends Crypt_Base
{
/**
* Block Length of the cipher
*
* @see Crypt_Base::block_size
* @var int
* @access private
*/
var $block_size = 8;
/**
* Key Length (in bytes)
*
* @see Crypt_Base::setKeyLength()
* @var int
* @access private
*/
var $key_length = 8;
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'DES';
/**
* The mcrypt specific name of the cipher
*
* @see Crypt_Base::cipher_name_mcrypt
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'des';
/**
* The OpenSSL names of the cipher / modes
*
* @see Crypt_Base::openssl_mode_names
* @var array
* @access private
*/
var $openssl_mode_names = array(
CRYPT_MODE_ECB => 'des-ecb',
CRYPT_MODE_CBC => 'des-cbc',
CRYPT_MODE_CFB => 'des-cfb',
CRYPT_MODE_OFB => 'des-ofb'
// CRYPT_MODE_CTR is undefined for DES
);
/**
* Optimizing value while CFB-encrypting
*
* @see Crypt_Base::cfb_init_len
* @var int
* @access private
*/
var $cfb_init_len = 500;
/**
* Switch for DES/3DES encryption
*
* Used only if $engine == CRYPT_DES_MODE_INTERNAL
*
* @see self::_setupKey()
* @see self::_processBlock()
* @var int
* @access private
*/
var $des_rounds = 1;
/**
* max possible size of $key
*
* @see self::setKey()
* @var string
* @access private
*/
var $key_length_max = 8;
/**
* The Key Schedule
*
* @see self::_setupKey()
* @var array
* @access private
*/
var $keys;
/**
* Shuffle table.
*
* For each byte value index, the entry holds an 8-byte string
* with each byte containing all bits in the same state as the
* corresponding bit in the index value.
*
* @see self::_processBlock()
* @see self::_setupKey()
* @var array
* @access private
*/
var $shuffle = array(
"\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF",
"\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF",
"\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF",
"\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF",
"\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF",
"\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF",
"\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF",
"\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
"\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF",
"\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF",
"\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF",
"\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF",
"\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF",
"\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF",
"\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF",
"\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF",
"\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF",
"\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF",
"\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF",
"\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF",
"\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF",
"\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF",
"\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF",
"\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF",
"\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF",
"\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF",
"\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF",
"\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF",
"\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF",
"\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF",
"\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF",
"\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
"\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF",
"\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF",
"\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF",
"\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF",
"\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF",
"\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF",
"\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF",
"\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF",
"\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF",
"\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF",
"\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF",
"\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF",
"\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF",
"\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF",
"\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF",
"\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF",
"\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF",
"\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF",
"\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF",
"\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF",
"\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF",
"\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF",
"\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF",
"\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF",
"\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF",
"\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF",
"\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF",
"\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF",
"\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF",
"\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF",
"\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF",
"\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
"\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF",
"\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF",
"\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF",
"\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF",
"\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF",
"\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF",
"\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF",
"\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF",
"\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF",
"\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF",
"\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF",
"\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF",
"\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF",
"\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF",
"\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF",
"\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF",
"\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF",
"\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF",
"\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF",
"\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF",
"\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF",
"\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF",
"\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF",
"\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF",
"\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF",
"\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF",
"\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF",
"\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF",
"\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF",
"\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF",
"\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF",
"\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF",
"\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF",
"\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF",
"\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF",
"\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF",
"\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF",
"\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF",
"\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF",
"\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF",
"\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF",
"\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF",
"\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF",
"\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF",
"\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF",
"\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF",
"\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF",
"\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF",
"\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF",
"\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF",
"\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF",
"\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF",
"\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF",
"\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF",
"\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF",
"\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF",
"\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF",
"\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF",
"\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF",
"\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF",
"\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF",
"\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF",
"\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF",
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
);
/**
* IP mapping helper table.
*
* Indexing this table with each source byte performs the initial bit permutation.
*
* @var array
* @access private
*/
var $ipmap = array(
0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31,
0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33,
0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71,
0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73,
0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35,
0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37,
0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75,
0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77,
0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1,
0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3,
0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1,
0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3,
0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5,
0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7,
0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5,
0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7,
0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39,
0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B,
0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79,
0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B,
0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D,
0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D,
0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9,
0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB,
0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9,
0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB,
0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD,
0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF,
0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD,
0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF
);
/**
* Inverse IP mapping helper table.
* Indexing this table with a byte value reverses the bit order.
*
* @var array
* @access private
*/
var $invipmap = array(
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
);
/**
* Pre-permuted S-box1
*
* Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the
* P table: concatenation can then be replaced by exclusive ORs.
*
* @var array
* @access private
*/
var $sbox1 = array(
0x00808200, 0x00000000, 0x00008000, 0x00808202,
0x00808002, 0x00008202, 0x00000002, 0x00008000,
0x00000200, 0x00808200, 0x00808202, 0x00000200,
0x00800202, 0x00808002, 0x00800000, 0x00000002,
0x00000202, 0x00800200, 0x00800200, 0x00008200,
0x00008200, 0x00808000, 0x00808000, 0x00800202,
0x00008002, 0x00800002, 0x00800002, 0x00008002,
0x00000000, 0x00000202, 0x00008202, 0x00800000,
0x00008000, 0x00808202, 0x00000002, 0x00808000,
0x00808200, 0x00800000, 0x00800000, 0x00000200,
0x00808002, 0x00008000, 0x00008200, 0x00800002,
0x00000200, 0x00000002, 0x00800202, 0x00008202,
0x00808202, 0x00008002, 0x00808000, 0x00800202,
0x00800002, 0x00000202, 0x00008202, 0x00808200,
0x00000202, 0x00800200, 0x00800200, 0x00000000,
0x00008002, 0x00008200, 0x00000000, 0x00808002
);
/**
* Pre-permuted S-box2
*
* @var array
* @access private
*/
var $sbox2 = array(
0x40084010, 0x40004000, 0x00004000, 0x00084010,
0x00080000, 0x00000010, 0x40080010, 0x40004010,
0x40000010, 0x40084010, 0x40084000, 0x40000000,
0x40004000, 0x00080000, 0x00000010, 0x40080010,
0x00084000, 0x00080010, 0x40004010, 0x00000000,
0x40000000, 0x00004000, 0x00084010, 0x40080000,
0x00080010, 0x40000010, 0x00000000, 0x00084000,
0x00004010, 0x40084000, 0x40080000, 0x00004010,
0x00000000, 0x00084010, 0x40080010, 0x00080000,
0x40004010, 0x40080000, 0x40084000, 0x00004000,
0x40080000, 0x40004000, 0x00000010, 0x40084010,
0x00084010, 0x00000010, 0x00004000, 0x40000000,
0x00004010, 0x40084000, 0x00080000, 0x40000010,
0x00080010, 0x40004010, 0x40000010, 0x00080010,
0x00084000, 0x00000000, 0x40004000, 0x00004010,
0x40000000, 0x40080010, 0x40084010, 0x00084000
);
/**
* Pre-permuted S-box3
*
* @var array
* @access private
*/
var $sbox3 = array(
0x00000104, 0x04010100, 0x00000000, 0x04010004,
0x04000100, 0x00000000, 0x00010104, 0x04000100,
0x00010004, 0x04000004, 0x04000004, 0x00010000,
0x04010104, 0x00010004, 0x04010000, 0x00000104,
0x04000000, 0x00000004, 0x04010100, 0x00000100,
0x00010100, 0x04010000, 0x04010004, 0x00010104,
0x04000104, 0x00010100, 0x00010000, 0x04000104,
0x00000004, 0x04010104, 0x00000100, 0x04000000,
0x04010100, 0x04000000, 0x00010004, 0x00000104,
0x00010000, 0x04010100, 0x04000100, 0x00000000,
0x00000100, 0x00010004, 0x04010104, 0x04000100,
0x04000004, 0x00000100, 0x00000000, 0x04010004,
0x04000104, 0x00010000, 0x04000000, 0x04010104,
0x00000004, 0x00010104, 0x00010100, 0x04000004,
0x04010000, 0x04000104, 0x00000104, 0x04010000,
0x00010104, 0x00000004, 0x04010004, 0x00010100
);
/**
* Pre-permuted S-box4
*
* @var array
* @access private
*/
var $sbox4 = array(
0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x00401040, 0x80400040, 0x80400000, 0x80001000,
0x00000000, 0x00401000, 0x00401000, 0x80401040,
0x80000040, 0x00000000, 0x00400040, 0x80400000,
0x80000000, 0x00001000, 0x00400000, 0x80401000,
0x00000040, 0x00400000, 0x80001000, 0x00001040,
0x80400040, 0x80000000, 0x00001040, 0x00400040,
0x00001000, 0x00401040, 0x80401040, 0x80000040,
0x00400040, 0x80400000, 0x00401000, 0x80401040,
0x80000040, 0x00000000, 0x00000000, 0x00401000,
0x00001040, 0x00400040, 0x80400040, 0x80000000,
0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x80401040, 0x80000040, 0x80000000, 0x00001000,
0x80400000, 0x80001000, 0x00401040, 0x80400040,
0x80001000, 0x00001040, 0x00400000, 0x80401000,
0x00000040, 0x00400000, 0x00001000, 0x00401040
);
/**
* Pre-permuted S-box5
*
* @var array
* @access private
*/
var $sbox5 = array(
0x00000080, 0x01040080, 0x01040000, 0x21000080,
0x00040000, 0x00000080, 0x20000000, 0x01040000,
0x20040080, 0x00040000, 0x01000080, 0x20040080,
0x21000080, 0x21040000, 0x00040080, 0x20000000,
0x01000000, 0x20040000, 0x20040000, 0x00000000,
0x20000080, 0x21040080, 0x21040080, 0x01000080,
0x21040000, 0x20000080, 0x00000000, 0x21000000,
0x01040080, 0x01000000, 0x21000000, 0x00040080,
0x00040000, 0x21000080, 0x00000080, 0x01000000,
0x20000000, 0x01040000, 0x21000080, 0x20040080,
0x01000080, 0x20000000, 0x21040000, 0x01040080,
0x20040080, 0x00000080, 0x01000000, 0x21040000,
0x21040080, 0x00040080, 0x21000000, 0x21040080,
0x01040000, 0x00000000, 0x20040000, 0x21000000,
0x00040080, 0x01000080, 0x20000080, 0x00040000,
0x00000000, 0x20040000, 0x01040080, 0x20000080
);
/**
* Pre-permuted S-box6
*
* @var array
* @access private
*/
var $sbox6 = array(
0x10000008, 0x10200000, 0x00002000, 0x10202008,
0x10200000, 0x00000008, 0x10202008, 0x00200000,
0x10002000, 0x00202008, 0x00200000, 0x10000008,
0x00200008, 0x10002000, 0x10000000, 0x00002008,
0x00000000, 0x00200008, 0x10002008, 0x00002000,
0x00202000, 0x10002008, 0x00000008, 0x10200008,
0x10200008, 0x00000000, 0x00202008, 0x10202000,
0x00002008, 0x00202000, 0x10202000, 0x10000000,
0x10002000, 0x00000008, 0x10200008, 0x00202000,
0x10202008, 0x00200000, 0x00002008, 0x10000008,
0x00200000, 0x10002000, 0x10000000, 0x00002008,
0x10000008, 0x10202008, 0x00202000, 0x10200000,
0x00202008, 0x10202000, 0x00000000, 0x10200008,
0x00000008, 0x00002000, 0x10200000, 0x00202008,
0x00002000, 0x00200008, 0x10002008, 0x00000000,
0x10202000, 0x10000000, 0x00200008, 0x10002008
);
/**
* Pre-permuted S-box7
*
* @var array
* @access private
*/
var $sbox7 = array(
0x00100000, 0x02100001, 0x02000401, 0x00000000,
0x00000400, 0x02000401, 0x00100401, 0x02100400,
0x02100401, 0x00100000, 0x00000000, 0x02000001,
0x00000001, 0x02000000, 0x02100001, 0x00000401,
0x02000400, 0x00100401, 0x00100001, 0x02000400,
0x02000001, 0x02100000, 0x02100400, 0x00100001,
0x02100000, 0x00000400, 0x00000401, 0x02100401,
0x00100400, 0x00000001, 0x02000000, 0x00100400,
0x02000000, 0x00100400, 0x00100000, 0x02000401,
0x02000401, 0x02100001, 0x02100001, 0x00000001,
0x00100001, 0x02000000, 0x02000400, 0x00100000,
0x02100400, 0x00000401, 0x00100401, 0x02100400,
0x00000401, 0x02000001, 0x02100401, 0x02100000,
0x00100400, 0x00000000, 0x00000001, 0x02100401,
0x00000000, 0x00100401, 0x02100000, 0x00000400,
0x02000001, 0x02000400, 0x00000400, 0x00100001
);
/**
* Pre-permuted S-box8
*
* @var array
* @access private
*/
var $sbox8 = array(
0x08000820, 0x00000800, 0x00020000, 0x08020820,
0x08000000, 0x08000820, 0x00000020, 0x08000000,
0x00020020, 0x08020000, 0x08020820, 0x00020800,
0x08020800, 0x00020820, 0x00000800, 0x00000020,
0x08020000, 0x08000020, 0x08000800, 0x00000820,
0x00020800, 0x00020020, 0x08020020, 0x08020800,
0x00000820, 0x00000000, 0x00000000, 0x08020020,
0x08000020, 0x08000800, 0x00020820, 0x00020000,
0x00020820, 0x00020000, 0x08020800, 0x00000800,
0x00000020, 0x08020020, 0x00000800, 0x00020820,
0x08000800, 0x00000020, 0x08000020, 0x08020000,
0x08020020, 0x08000000, 0x00020000, 0x08000820,
0x00000000, 0x08020820, 0x00020020, 0x08000020,
0x08020000, 0x08000800, 0x08000820, 0x00000000,
0x08020820, 0x00020800, 0x00020800, 0x00000820,
0x00000820, 0x00020020, 0x08000000, 0x08020800
);
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::isValidEngine()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
if ($this->key_length_max == 8) {
if ($engine == CRYPT_ENGINE_OPENSSL) {
$this->cipher_name_openssl_ecb = 'des-ecb';
$this->cipher_name_openssl = 'des-' . $this->_openssl_translate_mode();
}
}
return parent::isValidEngine($engine);
}
/**
* Sets the key.
*
* Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
* only use the first eight, if $key has more then eight characters in it, and pad $key with the
* null byte if it is less then eight characters long.
*
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
*
* If the key is not explicitly set, it'll be assumed to be all zero's.
*
* @see Crypt_Base::setKey()
* @access public
* @param string $key
*/
function setKey($key)
{
// We check/cut here only up to max length of the key.
// Key padding to the proper length will be done in _setupKey()
if (strlen($key) > $this->key_length_max) {
$key = substr($key, 0, $this->key_length_max);
}
// Sets the key
parent::setKey($key);
}
/**
* Encrypts a block
*
* @see Crypt_Base::_encryptBlock()
* @see Crypt_Base::encrypt()
* @see self::encrypt()
* @access private
* @param string $in
* @return string
*/
function _encryptBlock($in)
{
return $this->_processBlock($in, CRYPT_DES_ENCRYPT);
}
/**
* Decrypts a block
*
* @see Crypt_Base::_decryptBlock()
* @see Crypt_Base::decrypt()
* @see self::decrypt()
* @access private
* @param string $in
* @return string
*/
function _decryptBlock($in)
{
return $this->_processBlock($in, CRYPT_DES_DECRYPT);
}
/**
* Encrypts or decrypts a 64-bit block
*
* $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See
* {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
* idea of what this function does.
*
* @see self::_encryptBlock()
* @see self::_decryptBlock()
* @access private
* @param string $block
* @param int $mode
* @return string
*/
function _processBlock($block, $mode)
{
static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
if (!$sbox1) {
$sbox1 = array_map("intval", $this->sbox1);
$sbox2 = array_map("intval", $this->sbox2);
$sbox3 = array_map("intval", $this->sbox3);
$sbox4 = array_map("intval", $this->sbox4);
$sbox5 = array_map("intval", $this->sbox5);
$sbox6 = array_map("intval", $this->sbox6);
$sbox7 = array_map("intval", $this->sbox7);
$sbox8 = array_map("intval", $this->sbox8);
/* Merge $shuffle with $[inv]ipmap */
for ($i = 0; $i < 256; ++$i) {
$shuffleip[] = $this->shuffle[$this->ipmap[$i]];
$shuffleinvip[] = $this->shuffle[$this->invipmap[$i]];
}
}
$keys = $this->keys[$mode];
$ki = -1;
// Do the initial IP permutation.
$t = unpack('Nl/Nr', $block);
list($l, $r) = array($t['l'], $t['r']);
$block = ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
// Extract L0 and R0.
$t = unpack('Nl/Nr', $block);
list($l, $r) = array($t['l'], $t['r']);
for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
// Perform the 16 steps.
for ($i = 0; $i < 16; $i++) {
// start of "the Feistel (F) function" - see the following URL:
// http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
// Merge key schedule.
$b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki];
$b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[++$ki];
// S-box indexing.
$t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
$sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
$sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
$sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $l;
// end of "the Feistel (F) function"
$l = $r;
$r = $t;
}
// Last step should not permute L & R.
$t = $l;
$l = $r;
$r = $t;
}
// Perform the inverse IP permutation.
return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleinvip[($r >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleinvip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleinvip[ $r & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleinvip[ $l & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
}
/**
* Creates the key schedule
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) {
// already expanded
return;
}
$this->kl = array('key' => $this->key, 'des_rounds' => $this->des_rounds);
static $shifts = array( // number of key bits shifted per round
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
);
static $pc1map = array(
0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C,
0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E,
0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C,
0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E,
0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C,
0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E,
0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C,
0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E,
0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C,
0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E,
0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C,
0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E,
0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C,
0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E,
0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C,
0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E,
0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C,
0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E,
0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C,
0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E,
0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC,
0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE,
0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC,
0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE,
0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC,
0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE,
0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC,
0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE,
0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC,
0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE,
0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC,
0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE
);
// Mapping tables for the PC-2 transformation.
static $pc2mapc1 = array(
0x00000000, 0x00000400, 0x00200000, 0x00200400,
0x00000001, 0x00000401, 0x00200001, 0x00200401,
0x02000000, 0x02000400, 0x02200000, 0x02200400,
0x02000001, 0x02000401, 0x02200001, 0x02200401
);
static $pc2mapc2 = array(
0x00000000, 0x00000800, 0x08000000, 0x08000800,
0x00010000, 0x00010800, 0x08010000, 0x08010800,
0x00000000, 0x00000800, 0x08000000, 0x08000800,
0x00010000, 0x00010800, 0x08010000, 0x08010800,
0x00000100, 0x00000900, 0x08000100, 0x08000900,
0x00010100, 0x00010900, 0x08010100, 0x08010900,
0x00000100, 0x00000900, 0x08000100, 0x08000900,
0x00010100, 0x00010900, 0x08010100, 0x08010900,
0x00000010, 0x00000810, 0x08000010, 0x08000810,
0x00010010, 0x00010810, 0x08010010, 0x08010810,
0x00000010, 0x00000810, 0x08000010, 0x08000810,
0x00010010, 0x00010810, 0x08010010, 0x08010810,
0x00000110, 0x00000910, 0x08000110, 0x08000910,
0x00010110, 0x00010910, 0x08010110, 0x08010910,
0x00000110, 0x00000910, 0x08000110, 0x08000910,
0x00010110, 0x00010910, 0x08010110, 0x08010910,
0x00040000, 0x00040800, 0x08040000, 0x08040800,
0x00050000, 0x00050800, 0x08050000, 0x08050800,
0x00040000, 0x00040800, 0x08040000, 0x08040800,
0x00050000, 0x00050800, 0x08050000, 0x08050800,
0x00040100, 0x00040900, 0x08040100, 0x08040900,
0x00050100, 0x00050900, 0x08050100, 0x08050900,
0x00040100, 0x00040900, 0x08040100, 0x08040900,
0x00050100, 0x00050900, 0x08050100, 0x08050900,
0x00040010, 0x00040810, 0x08040010, 0x08040810,
0x00050010, 0x00050810, 0x08050010, 0x08050810,
0x00040010, 0x00040810, 0x08040010, 0x08040810,
0x00050010, 0x00050810, 0x08050010, 0x08050810,
0x00040110, 0x00040910, 0x08040110, 0x08040910,
0x00050110, 0x00050910, 0x08050110, 0x08050910,
0x00040110, 0x00040910, 0x08040110, 0x08040910,
0x00050110, 0x00050910, 0x08050110, 0x08050910,
0x01000000, 0x01000800, 0x09000000, 0x09000800,
0x01010000, 0x01010800, 0x09010000, 0x09010800,
0x01000000, 0x01000800, 0x09000000, 0x09000800,
0x01010000, 0x01010800, 0x09010000, 0x09010800,
0x01000100, 0x01000900, 0x09000100, 0x09000900,
0x01010100, 0x01010900, 0x09010100, 0x09010900,
0x01000100, 0x01000900, 0x09000100, 0x09000900,
0x01010100, 0x01010900, 0x09010100, 0x09010900,
0x01000010, 0x01000810, 0x09000010, 0x09000810,
0x01010010, 0x01010810, 0x09010010, 0x09010810,
0x01000010, 0x01000810, 0x09000010, 0x09000810,
0x01010010, 0x01010810, 0x09010010, 0x09010810,
0x01000110, 0x01000910, 0x09000110, 0x09000910,
0x01010110, 0x01010910, 0x09010110, 0x09010910,
0x01000110, 0x01000910, 0x09000110, 0x09000910,
0x01010110, 0x01010910, 0x09010110, 0x09010910,
0x01040000, 0x01040800, 0x09040000, 0x09040800,
0x01050000, 0x01050800, 0x09050000, 0x09050800,
0x01040000, 0x01040800, 0x09040000, 0x09040800,
0x01050000, 0x01050800, 0x09050000, 0x09050800,
0x01040100, 0x01040900, 0x09040100, 0x09040900,
0x01050100, 0x01050900, 0x09050100, 0x09050900,
0x01040100, 0x01040900, 0x09040100, 0x09040900,
0x01050100, 0x01050900, 0x09050100, 0x09050900,
0x01040010, 0x01040810, 0x09040010, 0x09040810,
0x01050010, 0x01050810, 0x09050010, 0x09050810,
0x01040010, 0x01040810, 0x09040010, 0x09040810,
0x01050010, 0x01050810, 0x09050010, 0x09050810,
0x01040110, 0x01040910, 0x09040110, 0x09040910,
0x01050110, 0x01050910, 0x09050110, 0x09050910,
0x01040110, 0x01040910, 0x09040110, 0x09040910,
0x01050110, 0x01050910, 0x09050110, 0x09050910
);
static $pc2mapc3 = array(
0x00000000, 0x00000004, 0x00001000, 0x00001004,
0x00000000, 0x00000004, 0x00001000, 0x00001004,
0x10000000, 0x10000004, 0x10001000, 0x10001004,
0x10000000, 0x10000004, 0x10001000, 0x10001004,
0x00000020, 0x00000024, 0x00001020, 0x00001024,
0x00000020, 0x00000024, 0x00001020, 0x00001024,
0x10000020, 0x10000024, 0x10001020, 0x10001024,
0x10000020, 0x10000024, 0x10001020, 0x10001024,
0x00080000, 0x00080004, 0x00081000, 0x00081004,
0x00080000, 0x00080004, 0x00081000, 0x00081004,
0x10080000, 0x10080004, 0x10081000, 0x10081004,
0x10080000, 0x10080004, 0x10081000, 0x10081004,
0x00080020, 0x00080024, 0x00081020, 0x00081024,
0x00080020, 0x00080024, 0x00081020, 0x00081024,
0x10080020, 0x10080024, 0x10081020, 0x10081024,
0x10080020, 0x10080024, 0x10081020, 0x10081024,
0x20000000, 0x20000004, 0x20001000, 0x20001004,
0x20000000, 0x20000004, 0x20001000, 0x20001004,
0x30000000, 0x30000004, 0x30001000, 0x30001004,
0x30000000, 0x30000004, 0x30001000, 0x30001004,
0x20000020, 0x20000024, 0x20001020, 0x20001024,
0x20000020, 0x20000024, 0x20001020, 0x20001024,
0x30000020, 0x30000024, 0x30001020, 0x30001024,
0x30000020, 0x30000024, 0x30001020, 0x30001024,
0x20080000, 0x20080004, 0x20081000, 0x20081004,
0x20080000, 0x20080004, 0x20081000, 0x20081004,
0x30080000, 0x30080004, 0x30081000, 0x30081004,
0x30080000, 0x30080004, 0x30081000, 0x30081004,
0x20080020, 0x20080024, 0x20081020, 0x20081024,
0x20080020, 0x20080024, 0x20081020, 0x20081024,
0x30080020, 0x30080024, 0x30081020, 0x30081024,
0x30080020, 0x30080024, 0x30081020, 0x30081024,
0x00000002, 0x00000006, 0x00001002, 0x00001006,
0x00000002, 0x00000006, 0x00001002, 0x00001006,
0x10000002, 0x10000006, 0x10001002, 0x10001006,
0x10000002, 0x10000006, 0x10001002, 0x10001006,
0x00000022, 0x00000026, 0x00001022, 0x00001026,
0x00000022, 0x00000026, 0x00001022, 0x00001026,
0x10000022, 0x10000026, 0x10001022, 0x10001026,
0x10000022, 0x10000026, 0x10001022, 0x10001026,
0x00080002, 0x00080006, 0x00081002, 0x00081006,
0x00080002, 0x00080006, 0x00081002, 0x00081006,
0x10080002, 0x10080006, 0x10081002, 0x10081006,
0x10080002, 0x10080006, 0x10081002, 0x10081006,
0x00080022, 0x00080026, 0x00081022, 0x00081026,
0x00080022, 0x00080026, 0x00081022, 0x00081026,
0x10080022, 0x10080026, 0x10081022, 0x10081026,
0x10080022, 0x10080026, 0x10081022, 0x10081026,
0x20000002, 0x20000006, 0x20001002, 0x20001006,
0x20000002, 0x20000006, 0x20001002, 0x20001006,
0x30000002, 0x30000006, 0x30001002, 0x30001006,
0x30000002, 0x30000006, 0x30001002, 0x30001006,
0x20000022, 0x20000026, 0x20001022, 0x20001026,
0x20000022, 0x20000026, 0x20001022, 0x20001026,
0x30000022, 0x30000026, 0x30001022, 0x30001026,
0x30000022, 0x30000026, 0x30001022, 0x30001026,
0x20080002, 0x20080006, 0x20081002, 0x20081006,
0x20080002, 0x20080006, 0x20081002, 0x20081006,
0x30080002, 0x30080006, 0x30081002, 0x30081006,
0x30080002, 0x30080006, 0x30081002, 0x30081006,
0x20080022, 0x20080026, 0x20081022, 0x20081026,
0x20080022, 0x20080026, 0x20081022, 0x20081026,
0x30080022, 0x30080026, 0x30081022, 0x30081026,
0x30080022, 0x30080026, 0x30081022, 0x30081026
);
static $pc2mapc4 = array(
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208
);
static $pc2mapd1 = array(
0x00000000, 0x00000001, 0x08000000, 0x08000001,
0x00200000, 0x00200001, 0x08200000, 0x08200001,
0x00000002, 0x00000003, 0x08000002, 0x08000003,
0x00200002, 0x00200003, 0x08200002, 0x08200003
);
static $pc2mapd2 = array(
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04
);
static $pc2mapd3 = array(
0x00000000, 0x00010000, 0x02000000, 0x02010000,
0x00000020, 0x00010020, 0x02000020, 0x02010020,
0x00040000, 0x00050000, 0x02040000, 0x02050000,
0x00040020, 0x00050020, 0x02040020, 0x02050020,
0x00002000, 0x00012000, 0x02002000, 0x02012000,
0x00002020, 0x00012020, 0x02002020, 0x02012020,
0x00042000, 0x00052000, 0x02042000, 0x02052000,
0x00042020, 0x00052020, 0x02042020, 0x02052020,
0x00000000, 0x00010000, 0x02000000, 0x02010000,
0x00000020, 0x00010020, 0x02000020, 0x02010020,
0x00040000, 0x00050000, 0x02040000, 0x02050000,
0x00040020, 0x00050020, 0x02040020, 0x02050020,
0x00002000, 0x00012000, 0x02002000, 0x02012000,
0x00002020, 0x00012020, 0x02002020, 0x02012020,
0x00042000, 0x00052000, 0x02042000, 0x02052000,
0x00042020, 0x00052020, 0x02042020, 0x02052020,
0x00000010, 0x00010010, 0x02000010, 0x02010010,
0x00000030, 0x00010030, 0x02000030, 0x02010030,
0x00040010, 0x00050010, 0x02040010, 0x02050010,
0x00040030, 0x00050030, 0x02040030, 0x02050030,
0x00002010, 0x00012010, 0x02002010, 0x02012010,
0x00002030, 0x00012030, 0x02002030, 0x02012030,
0x00042010, 0x00052010, 0x02042010, 0x02052010,
0x00042030, 0x00052030, 0x02042030, 0x02052030,
0x00000010, 0x00010010, 0x02000010, 0x02010010,
0x00000030, 0x00010030, 0x02000030, 0x02010030,
0x00040010, 0x00050010, 0x02040010, 0x02050010,
0x00040030, 0x00050030, 0x02040030, 0x02050030,
0x00002010, 0x00012010, 0x02002010, 0x02012010,
0x00002030, 0x00012030, 0x02002030, 0x02012030,
0x00042010, 0x00052010, 0x02042010, 0x02052010,
0x00042030, 0x00052030, 0x02042030, 0x02052030,
0x20000000, 0x20010000, 0x22000000, 0x22010000,
0x20000020, 0x20010020, 0x22000020, 0x22010020,
0x20040000, 0x20050000, 0x22040000, 0x22050000,
0x20040020, 0x20050020, 0x22040020, 0x22050020,
0x20002000, 0x20012000, 0x22002000, 0x22012000,
0x20002020, 0x20012020, 0x22002020, 0x22012020,
0x20042000, 0x20052000, 0x22042000, 0x22052000,
0x20042020, 0x20052020, 0x22042020, 0x22052020,
0x20000000, 0x20010000, 0x22000000, 0x22010000,
0x20000020, 0x20010020, 0x22000020, 0x22010020,
0x20040000, 0x20050000, 0x22040000, 0x22050000,
0x20040020, 0x20050020, 0x22040020, 0x22050020,
0x20002000, 0x20012000, 0x22002000, 0x22012000,
0x20002020, 0x20012020, 0x22002020, 0x22012020,
0x20042000, 0x20052000, 0x22042000, 0x22052000,
0x20042020, 0x20052020, 0x22042020, 0x22052020,
0x20000010, 0x20010010, 0x22000010, 0x22010010,
0x20000030, 0x20010030, 0x22000030, 0x22010030,
0x20040010, 0x20050010, 0x22040010, 0x22050010,
0x20040030, 0x20050030, 0x22040030, 0x22050030,
0x20002010, 0x20012010, 0x22002010, 0x22012010,
0x20002030, 0x20012030, 0x22002030, 0x22012030,
0x20042010, 0x20052010, 0x22042010, 0x22052010,
0x20042030, 0x20052030, 0x22042030, 0x22052030,
0x20000010, 0x20010010, 0x22000010, 0x22010010,
0x20000030, 0x20010030, 0x22000030, 0x22010030,
0x20040010, 0x20050010, 0x22040010, 0x22050010,
0x20040030, 0x20050030, 0x22040030, 0x22050030,
0x20002010, 0x20012010, 0x22002010, 0x22012010,
0x20002030, 0x20012030, 0x22002030, 0x22012030,
0x20042010, 0x20052010, 0x22042010, 0x22052010,
0x20042030, 0x20052030, 0x22042030, 0x22052030
);
static $pc2mapd4 = array(
0x00000000, 0x00000400, 0x01000000, 0x01000400,
0x00000000, 0x00000400, 0x01000000, 0x01000400,
0x00000100, 0x00000500, 0x01000100, 0x01000500,
0x00000100, 0x00000500, 0x01000100, 0x01000500,
0x10000000, 0x10000400, 0x11000000, 0x11000400,
0x10000000, 0x10000400, 0x11000000, 0x11000400,
0x10000100, 0x10000500, 0x11000100, 0x11000500,
0x10000100, 0x10000500, 0x11000100, 0x11000500,
0x00080000, 0x00080400, 0x01080000, 0x01080400,
0x00080000, 0x00080400, 0x01080000, 0x01080400,
0x00080100, 0x00080500, 0x01080100, 0x01080500,
0x00080100, 0x00080500, 0x01080100, 0x01080500,
0x10080000, 0x10080400, 0x11080000, 0x11080400,
0x10080000, 0x10080400, 0x11080000, 0x11080400,
0x10080100, 0x10080500, 0x11080100, 0x11080500,
0x10080100, 0x10080500, 0x11080100, 0x11080500,
0x00000008, 0x00000408, 0x01000008, 0x01000408,
0x00000008, 0x00000408, 0x01000008, 0x01000408,
0x00000108, 0x00000508, 0x01000108, 0x01000508,
0x00000108, 0x00000508, 0x01000108, 0x01000508,
0x10000008, 0x10000408, 0x11000008, 0x11000408,
0x10000008, 0x10000408, 0x11000008, 0x11000408,
0x10000108, 0x10000508, 0x11000108, 0x11000508,
0x10000108, 0x10000508, 0x11000108, 0x11000508,
0x00080008, 0x00080408, 0x01080008, 0x01080408,
0x00080008, 0x00080408, 0x01080008, 0x01080408,
0x00080108, 0x00080508, 0x01080108, 0x01080508,
0x00080108, 0x00080508, 0x01080108, 0x01080508,
0x10080008, 0x10080408, 0x11080008, 0x11080408,
0x10080008, 0x10080408, 0x11080008, 0x11080408,
0x10080108, 0x10080508, 0x11080108, 0x11080508,
0x10080108, 0x10080508, 0x11080108, 0x11080508,
0x00001000, 0x00001400, 0x01001000, 0x01001400,
0x00001000, 0x00001400, 0x01001000, 0x01001400,
0x00001100, 0x00001500, 0x01001100, 0x01001500,
0x00001100, 0x00001500, 0x01001100, 0x01001500,
0x10001000, 0x10001400, 0x11001000, 0x11001400,
0x10001000, 0x10001400, 0x11001000, 0x11001400,
0x10001100, 0x10001500, 0x11001100, 0x11001500,
0x10001100, 0x10001500, 0x11001100, 0x11001500,
0x00081000, 0x00081400, 0x01081000, 0x01081400,
0x00081000, 0x00081400, 0x01081000, 0x01081400,
0x00081100, 0x00081500, 0x01081100, 0x01081500,
0x00081100, 0x00081500, 0x01081100, 0x01081500,
0x10081000, 0x10081400, 0x11081000, 0x11081400,
0x10081000, 0x10081400, 0x11081000, 0x11081400,
0x10081100, 0x10081500, 0x11081100, 0x11081500,
0x10081100, 0x10081500, 0x11081100, 0x11081500,
0x00001008, 0x00001408, 0x01001008, 0x01001408,
0x00001008, 0x00001408, 0x01001008, 0x01001408,
0x00001108, 0x00001508, 0x01001108, 0x01001508,
0x00001108, 0x00001508, 0x01001108, 0x01001508,
0x10001008, 0x10001408, 0x11001008, 0x11001408,
0x10001008, 0x10001408, 0x11001008, 0x11001408,
0x10001108, 0x10001508, 0x11001108, 0x11001508,
0x10001108, 0x10001508, 0x11001108, 0x11001508,
0x00081008, 0x00081408, 0x01081008, 0x01081408,
0x00081008, 0x00081408, 0x01081008, 0x01081408,
0x00081108, 0x00081508, 0x01081108, 0x01081508,
0x00081108, 0x00081508, 0x01081108, 0x01081508,
0x10081008, 0x10081408, 0x11081008, 0x11081408,
0x10081008, 0x10081408, 0x11081008, 0x11081408,
0x10081108, 0x10081508, 0x11081108, 0x11081508,
0x10081108, 0x10081508, 0x11081108, 0x11081508
);
$keys = array();
for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
// pad the key and remove extra characters as appropriate.
$key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0");
// Perform the PC/1 transformation and compute C and D.
$t = unpack('Nl/Nr', $key);
list($l, $r) = array($t['l'], $t['r']);
$key = ($this->shuffle[$pc1map[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") |
($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") |
($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") |
($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") |
($this->shuffle[$pc1map[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") |
($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") |
($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") |
($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00");
$key = unpack('Nc/Nd', $key);
$c = ( $key['c'] >> 4) & 0x0FFFFFFF;
$d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F);
$keys[$des_round] = array(
CRYPT_DES_ENCRYPT => array(),
CRYPT_DES_DECRYPT => array_fill(0, 32, 0)
);
for ($i = 0, $ki = 31; $i < 16; ++$i, $ki-= 2) {
$c <<= $shifts[$i];
$c = ($c | ($c >> 28)) & 0x0FFFFFFF;
$d <<= $shifts[$i];
$d = ($d | ($d >> 28)) & 0x0FFFFFFF;
// Perform the PC-2 transformation.
$cp = $pc2mapc1[ $c >> 24 ] | $pc2mapc2[($c >> 16) & 0xFF] |
$pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[ $c & 0xFF];
$dp = $pc2mapd1[ $d >> 24 ] | $pc2mapd2[($d >> 16) & 0xFF] |
$pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF];
// Reorder: odd bytes/even bytes. Push the result in key schedule.
$val1 = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) |
(($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF);
$val2 = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) |
(($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF);
$keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val1;
$keys[$des_round][CRYPT_DES_DECRYPT][$ki - 1] = $val1;
$keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val2;
$keys[$des_round][CRYPT_DES_DECRYPT][$ki ] = $val2;
}
}
switch ($this->des_rounds) {
case 3: // 3DES keys
$this->keys = array(
CRYPT_DES_ENCRYPT => array_merge(
$keys[0][CRYPT_DES_ENCRYPT],
$keys[1][CRYPT_DES_DECRYPT],
$keys[2][CRYPT_DES_ENCRYPT]
),
CRYPT_DES_DECRYPT => array_merge(
$keys[2][CRYPT_DES_DECRYPT],
$keys[1][CRYPT_DES_ENCRYPT],
$keys[0][CRYPT_DES_DECRYPT]
)
);
break;
// case 1: // DES keys
default:
$this->keys = array(
CRYPT_DES_ENCRYPT => $keys[0][CRYPT_DES_ENCRYPT],
CRYPT_DES_DECRYPT => $keys[0][CRYPT_DES_DECRYPT]
);
}
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* @see Crypt_Base::_setupInlineCrypt()
* @access private
*/
function _setupInlineCrypt()
{
$lambda_functions =& Crypt_DES::_getLambdaFunctions();
// Engine configuration for:
// - DES ($des_rounds == 1) or
// - 3DES ($des_rounds == 3)
$des_rounds = $this->des_rounds;
// We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
// (Currently, for Crypt_DES, one generated $lambda_function cost on php5.5@32bit ~135kb unfreeable mem and ~230kb on php5.5@64bit)
// (Currently, for Crypt_TripleDES, one generated $lambda_function cost on php5.5@32bit ~240kb unfreeable mem and ~340kb on php5.5@64bit)
// After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one
$gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );
// Generation of a unique hash for our generated code
$code_hash = "Crypt_DES, $des_rounds, {$this->mode}";
if ($gen_hi_opt_code) {
// For hi-optimized code, we create for each combination of
// $mode, $des_rounds and $this->key its own encrypt/decrypt function.
// After max 10 hi-optimized functions, we create generic
// (still very fast.. but not ultra) functions for each $mode/$des_rounds
// Currently 2 * 5 generic functions will be then max. possible.
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
// Is there a re-usable $lambda_functions in there? If not, we have to create it.
if (!isset($lambda_functions[$code_hash])) {
// Init code for both, encrypt and decrypt.
$init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
if (!$sbox1) {
$sbox1 = array_map("intval", $self->sbox1);
$sbox2 = array_map("intval", $self->sbox2);
$sbox3 = array_map("intval", $self->sbox3);
$sbox4 = array_map("intval", $self->sbox4);
$sbox5 = array_map("intval", $self->sbox5);
$sbox6 = array_map("intval", $self->sbox6);
$sbox7 = array_map("intval", $self->sbox7);
$sbox8 = array_map("intval", $self->sbox8);'
/* Merge $shuffle with $[inv]ipmap */ . '
for ($i = 0; $i < 256; ++$i) {
$shuffleip[] = $self->shuffle[$self->ipmap[$i]];
$shuffleinvip[] = $self->shuffle[$self->invipmap[$i]];
}
}
';
switch (true) {
case $gen_hi_opt_code:
// In Hi-optimized code mode, we use our [3]DES key schedule as hardcoded integers.
// No futher initialisation of the $keys schedule is necessary.
// That is the extra performance boost.
$k = array(
CRYPT_DES_ENCRYPT => $this->keys[CRYPT_DES_ENCRYPT],
CRYPT_DES_DECRYPT => $this->keys[CRYPT_DES_DECRYPT]
);
$init_encrypt = '';
$init_decrypt = '';
break;
default:
// In generic optimized code mode, we have to use, as the best compromise [currently],
// our key schedule as $ke/$kd arrays. (with hardcoded indexes...)
$k = array(
CRYPT_DES_ENCRYPT => array(),
CRYPT_DES_DECRYPT => array()
);
for ($i = 0, $c = count($this->keys[CRYPT_DES_ENCRYPT]); $i < $c; ++$i) {
$k[CRYPT_DES_ENCRYPT][$i] = '$ke[' . $i . ']';
$k[CRYPT_DES_DECRYPT][$i] = '$kd[' . $i . ']';
}
$init_encrypt = '$ke = $self->keys[CRYPT_DES_ENCRYPT];';
$init_decrypt = '$kd = $self->keys[CRYPT_DES_DECRYPT];';
break;
}
// Creating code for en- and decryption.
$crypt_block = array();
foreach (array(CRYPT_DES_ENCRYPT, CRYPT_DES_DECRYPT) as $c) {
/* Do the initial IP permutation. */
$crypt_block[$c] = '
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
$in = unpack("N*",
($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01")
);
' . /* Extract L0 and R0 */ '
$l = $in[1];
$r = $in[2];
';
$l = '$l';
$r = '$r';
// Perform DES or 3DES.
for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) {
// Perform the 16 steps.
for ($i = 0; $i < 16; ++$i) {
// start of "the Feistel (F) function" - see the following URL:
// http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
// Merge key schedule.
$crypt_block[$c].= '
$b1 = ((' . $r . ' >> 3) & 0x1FFFFFFF) ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . ';
$b2 = ((' . $r . ' >> 31) & 0x00000001) ^ (' . $r . ' << 1) ^ ' . $k[$c][++$ki] . ';' .
/* S-box indexing. */
$l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
$sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
$sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
$sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ ' . $l . ';
';
// end of "the Feistel (F) function"
// swap L & R
list($l, $r) = array($r, $l);
}
list($l, $r) = array($r, $l);
}
// Perform the inverse IP permutation.
$crypt_block[$c].= '$in =
($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleinvip[($l >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleinvip[($r >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleinvip[ $l & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleinvip[ $r & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
';
}
// Creates the inline-crypt function
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => $init_crypt,
'init_encrypt' => $init_encrypt,
'init_decrypt' => $init_decrypt,
'encrypt_block' => $crypt_block[CRYPT_DES_ENCRYPT],
'decrypt_block' => $crypt_block[CRYPT_DES_DECRYPT]
)
);
}
// Set the inline-crypt function as callback in: $this->inline_crypt
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
================================================
FILE: assets/libraries/phpseclib/Crypt/Hash.php
================================================
* setKey('abcdefg');
*
* echo base64_encode($hash->hash('abcdefg'));
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_Hash
* @author Jim Wigginton
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**#@+
* @access private
* @see self::Crypt_Hash()
*/
/**
* Toggles the internal implementation
*/
define('CRYPT_HASH_MODE_INTERNAL', 1);
/**
* Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
*/
define('CRYPT_HASH_MODE_MHASH', 2);
/**
* Toggles the hash() implementation, which works on PHP 5.1.2+.
*/
define('CRYPT_HASH_MODE_HASH', 3);
/**#@-*/
/**
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
*
* @package Crypt_Hash
* @author Jim Wigginton
* @access public
*/
class Crypt_Hash
{
/**
* Hash Parameter
*
* @see self::setHash()
* @var int
* @access private
*/
var $hashParam;
/**
* Byte-length of compression blocks / key (Internal HMAC)
*
* @see self::setAlgorithm()
* @var int
* @access private
*/
var $b;
/**
* Byte-length of hash output (Internal HMAC)
*
* @see self::setHash()
* @var int
* @access private
*/
var $l = false;
/**
* Hash Algorithm
*
* @see self::setHash()
* @var string
* @access private
*/
var $hash;
/**
* Key
*
* @see self::setKey()
* @var string
* @access private
*/
var $key = false;
/**
* Computed Key
*
* @see self::_computeKey()
* @var string
* @access private
*/
var $computedKey = false;
/**
* Outer XOR (Internal HMAC)
*
* @see self::setKey()
* @var string
* @access private
*/
var $opad;
/**
* Inner XOR (Internal HMAC)
*
* @see self::setKey()
* @var string
* @access private
*/
var $ipad;
/**
* Engine
*
* @see self::setHash()
* @var string
* @access private
*/
var $engine;
/**
* Default Constructor.
*
* @param string $hash
* @return Crypt_Hash
* @access public
*/
function __construct($hash = 'sha1')
{
if (!defined('CRYPT_HASH_MODE')) {
switch (true) {
case extension_loaded('hash'):
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
break;
case extension_loaded('mhash'):
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
break;
default:
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
}
}
$this->setHash($hash);
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param int $mode
* @access public
*/
function Crypt_Hash($hash = 'sha1')
{
$this->__construct($hash);
}
/**
* Sets the key for HMACs
*
* Keys can be of any length.
*
* @access public
* @param string $key
*/
function setKey($key = false)
{
$this->key = $key;
$this->_computeKey();
}
/**
* Pre-compute the key used by the HMAC
*
* Quoting http://tools.ietf.org/html/rfc2104#section-2, "Applications that use keys longer than B bytes
* will first hash the key using H and then use the resultant L byte string as the actual key to HMAC."
*
* As documented in https://www.reddit.com/r/PHP/comments/9nct2l/symfonypolyfill_hash_pbkdf2_correct_fix_for/
* when doing an HMAC multiple times it's faster to compute the hash once instead of computing it during
* every call
*
* @access private
*/
function _computeKey()
{
if ($this->key === false) {
$this->computedKey = false;
return;
}
if (strlen($this->key) <= $this->b) {
$this->computedKey = $this->key;
return;
}
switch ($this->engine) {
case CRYPT_HASH_MODE_MHASH:
$this->computedKey = mhash($this->hash, $this->key);
break;
case CRYPT_HASH_MODE_HASH:
$this->computedKey = hash($this->hash, $this->key, true);
break;
case CRYPT_HASH_MODE_INTERNAL:
$this->computedKey = call_user_func($this->hash, $this->key);
}
}
/**
* Gets the hash function.
*
* As set by the constructor or by the setHash() method.
*
* @access public
* @return string
*/
function getHash()
{
return $this->hashParam;
}
/**
* Sets the hash function.
*
* @access public
* @param string $hash
*/
function setHash($hash)
{
$this->hashParam = $hash = strtolower($hash);
switch ($hash) {
case 'md5-96':
case 'sha1-96':
case 'sha256-96':
case 'sha512-96':
$hash = substr($hash, 0, -3);
$this->l = 12; // 96 / 8 = 12
break;
case 'md2':
case 'md5':
$this->l = 16;
break;
case 'sha1':
$this->l = 20;
break;
case 'sha256':
$this->l = 32;
break;
case 'sha384':
$this->l = 48;
break;
case 'sha512':
$this->l = 64;
}
switch ($hash) {
case 'md2-96':
case 'md2':
$this->b = 16;
case 'md5-96':
case 'sha1-96':
case 'sha224-96':
case 'sha256-96':
case 'md2':
case 'md5':
case 'sha1':
case 'sha224':
case 'sha256':
$this->b = 64;
break;
default:
$this->b = 128;
}
switch ($hash) {
case 'md2':
$this->engine = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
break;
case 'sha384':
case 'sha512':
$this->engine = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
break;
default:
$this->engine = CRYPT_HASH_MODE;
}
switch ($this->engine) {
case CRYPT_HASH_MODE_MHASH:
switch ($hash) {
case 'md5':
$this->hash = MHASH_MD5;
break;
case 'sha256':
$this->hash = MHASH_SHA256;
break;
case 'sha1':
default:
$this->hash = MHASH_SHA1;
}
$this->_computeKey();
return;
case CRYPT_HASH_MODE_HASH:
switch ($hash) {
case 'md5':
$this->hash = 'md5';
return;
case 'md2':
case 'sha256':
case 'sha384':
case 'sha512':
$this->hash = $hash;
return;
case 'sha1':
default:
$this->hash = 'sha1';
}
$this->_computeKey();
return;
}
switch ($hash) {
case 'md2':
$this->hash = array($this, '_md2');
break;
case 'md5':
$this->hash = array($this, '_md5');
break;
case 'sha256':
$this->hash = array($this, '_sha256');
break;
case 'sha384':
case 'sha512':
$this->hash = array($this, '_sha512');
break;
case 'sha1':
default:
$this->hash = array($this, '_sha1');
}
$this->ipad = str_repeat(chr(0x36), $this->b);
$this->opad = str_repeat(chr(0x5C), $this->b);
$this->_computeKey();
}
/**
* Compute the HMAC.
*
* @access public
* @param string $text
* @return string
*/
function hash($text)
{
if (!empty($this->key) || is_string($this->key)) {
switch ($this->engine) {
case CRYPT_HASH_MODE_MHASH:
$output = mhash($this->hash, $text, $this->computedKey);
break;
case CRYPT_HASH_MODE_HASH:
$output = hash_hmac($this->hash, $text, $this->computedKey, true);
break;
case CRYPT_HASH_MODE_INTERNAL:
$key = str_pad($this->computedKey, $this->b, chr(0)); // step 1
$temp = $this->ipad ^ $key; // step 2
$temp .= $text; // step 3
$temp = call_user_func($this->hash, $temp); // step 4
$output = $this->opad ^ $key; // step 5
$output.= $temp; // step 6
$output = call_user_func($this->hash, $output); // step 7
}
} else {
switch ($this->engine) {
case CRYPT_HASH_MODE_MHASH:
$output = mhash($this->hash, $text);
break;
case CRYPT_HASH_MODE_HASH:
$output = hash($this->hash, $text, true);
break;
case CRYPT_HASH_MODE_INTERNAL:
$output = call_user_func($this->hash, $text);
}
}
return substr($output, 0, $this->l);
}
/**
* Returns the hash length (in bytes)
*
* @access public
* @return int
*/
function getLength()
{
return $this->l;
}
/**
* Wrapper for MD5
*
* @access private
* @param string $m
*/
function _md5($m)
{
return pack('H*', md5($m));
}
/**
* Wrapper for SHA1
*
* @access private
* @param string $m
*/
function _sha1($m)
{
return pack('H*', sha1($m));
}
/**
* Pure-PHP implementation of MD2
*
* See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
*
* @access private
* @param string $m
*/
function _md2($m)
{
static $s = array(
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
31, 26, 219, 153, 141, 51, 159, 17, 131, 20
);
// Step 1. Append Padding Bytes
$pad = 16 - (strlen($m) & 0xF);
$m.= str_repeat(chr($pad), $pad);
$length = strlen($m);
// Step 2. Append Checksum
$c = str_repeat(chr(0), 16);
$l = chr(0);
for ($i = 0; $i < $length; $i+= 16) {
for ($j = 0; $j < 16; $j++) {
// RFC1319 incorrectly states that C[j] should be set to S[c xor L]
//$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
// per , however, C[j] should be set to S[c xor L] xor C[j]
$c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
$l = $c[$j];
}
}
$m.= $c;
$length+= 16;
// Step 3. Initialize MD Buffer
$x = str_repeat(chr(0), 48);
// Step 4. Process Message in 16-Byte Blocks
for ($i = 0; $i < $length; $i+= 16) {
for ($j = 0; $j < 16; $j++) {
$x[$j + 16] = $m[$i + $j];
$x[$j + 32] = $x[$j + 16] ^ $x[$j];
}
$t = chr(0);
for ($j = 0; $j < 18; $j++) {
for ($k = 0; $k < 48; $k++) {
$x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
//$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
}
$t = chr(ord($t) + $j);
}
}
// Step 5. Output
return substr($x, 0, 16);
}
/**
* Pure-PHP implementation of SHA256
*
* See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
*
* @access private
* @param string $m
*/
function _sha256($m)
{
if (extension_loaded('suhosin')) {
return pack('H*', sha256($m));
}
// Initialize variables
$hash = array(
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
);
// Initialize table of round constants
// (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
static $k = array(
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
);
// Pre-processing
$length = strlen($m);
// to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
$m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
$m[$length] = chr(0x80);
// we don't support hashing strings 512MB long
$m.= pack('N2', 0, $length << 3);
// Process the message in successive 512-bit chunks
$chunks = str_split($m, 64);
foreach ($chunks as $chunk) {
$w = array();
for ($i = 0; $i < 16; $i++) {
extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
$w[] = $temp;
}
// Extend the sixteen 32-bit words into sixty-four 32-bit words
for ($i = 16; $i < 64; $i++) {
// @codingStandardsIgnoreStart
$s0 = $this->_rightRotate($w[$i - 15], 7) ^
$this->_rightRotate($w[$i - 15], 18) ^
$this->_rightShift( $w[$i - 15], 3);
$s1 = $this->_rightRotate($w[$i - 2], 17) ^
$this->_rightRotate($w[$i - 2], 19) ^
$this->_rightShift( $w[$i - 2], 10);
// @codingStandardsIgnoreEnd
$w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
}
// Initialize hash value for this chunk
list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
// Main loop
for ($i = 0; $i < 64; $i++) {
$s0 = $this->_rightRotate($a, 2) ^
$this->_rightRotate($a, 13) ^
$this->_rightRotate($a, 22);
$maj = ($a & $b) ^
($a & $c) ^
($b & $c);
$t2 = $this->_add($s0, $maj);
$s1 = $this->_rightRotate($e, 6) ^
$this->_rightRotate($e, 11) ^
$this->_rightRotate($e, 25);
$ch = ($e & $f) ^
($this->_not($e) & $g);
$t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
$h = $g;
$g = $f;
$f = $e;
$e = $this->_add($d, $t1);
$d = $c;
$c = $b;
$b = $a;
$a = $this->_add($t1, $t2);
}
// Add this chunk's hash to result so far
$hash = array(
$this->_add($hash[0], $a),
$this->_add($hash[1], $b),
$this->_add($hash[2], $c),
$this->_add($hash[3], $d),
$this->_add($hash[4], $e),
$this->_add($hash[5], $f),
$this->_add($hash[6], $g),
$this->_add($hash[7], $h)
);
}
// Produce the final hash value (big-endian)
return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
}
/**
* Pure-PHP implementation of SHA384 and SHA512
*
* @access private
* @param string $m
*/
function _sha512($m)
{
if (!class_exists('Math_BigInteger')) {
include_once 'Math/BigInteger.php';
}
static $init384, $init512, $k;
if (!isset($k)) {
// Initialize variables
$init384 = array( // initial values for SHA384
'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
'67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
);
$init512 = array( // initial values for SHA512
'6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
'510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
);
for ($i = 0; $i < 8; $i++) {
$init384[$i] = new Math_BigInteger($init384[$i], 16);
$init384[$i]->setPrecision(64);
$init512[$i] = new Math_BigInteger($init512[$i], 16);
$init512[$i]->setPrecision(64);
}
// Initialize table of round constants
// (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
$k = array(
'428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
'3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
'72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
'2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
'983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
'27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
'650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
'19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
'391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
'748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
'90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
'06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
'28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
'4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
);
for ($i = 0; $i < 80; $i++) {
$k[$i] = new Math_BigInteger($k[$i], 16);
}
}
$hash = $this->l == 48 ? $init384 : $init512;
// Pre-processing
$length = strlen($m);
// to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
$m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
$m[$length] = chr(0x80);
// we don't support hashing strings 512MB long
$m.= pack('N4', 0, 0, 0, $length << 3);
// Process the message in successive 1024-bit chunks
$chunks = str_split($m, 128);
foreach ($chunks as $chunk) {
$w = array();
for ($i = 0; $i < 16; $i++) {
$temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
$temp->setPrecision(64);
$w[] = $temp;
}
// Extend the sixteen 32-bit words into eighty 32-bit words
for ($i = 16; $i < 80; $i++) {
$temp = array(
$w[$i - 15]->bitwise_rightRotate(1),
$w[$i - 15]->bitwise_rightRotate(8),
$w[$i - 15]->bitwise_rightShift(7)
);
$s0 = $temp[0]->bitwise_xor($temp[1]);
$s0 = $s0->bitwise_xor($temp[2]);
$temp = array(
$w[$i - 2]->bitwise_rightRotate(19),
$w[$i - 2]->bitwise_rightRotate(61),
$w[$i - 2]->bitwise_rightShift(6)
);
$s1 = $temp[0]->bitwise_xor($temp[1]);
$s1 = $s1->bitwise_xor($temp[2]);
$w[$i] = $w[$i - 16]->copy();
$w[$i] = $w[$i]->add($s0);
$w[$i] = $w[$i]->add($w[$i - 7]);
$w[$i] = $w[$i]->add($s1);
}
// Initialize hash value for this chunk
$a = $hash[0]->copy();
$b = $hash[1]->copy();
$c = $hash[2]->copy();
$d = $hash[3]->copy();
$e = $hash[4]->copy();
$f = $hash[5]->copy();
$g = $hash[6]->copy();
$h = $hash[7]->copy();
// Main loop
for ($i = 0; $i < 80; $i++) {
$temp = array(
$a->bitwise_rightRotate(28),
$a->bitwise_rightRotate(34),
$a->bitwise_rightRotate(39)
);
$s0 = $temp[0]->bitwise_xor($temp[1]);
$s0 = $s0->bitwise_xor($temp[2]);
$temp = array(
$a->bitwise_and($b),
$a->bitwise_and($c),
$b->bitwise_and($c)
);
$maj = $temp[0]->bitwise_xor($temp[1]);
$maj = $maj->bitwise_xor($temp[2]);
$t2 = $s0->add($maj);
$temp = array(
$e->bitwise_rightRotate(14),
$e->bitwise_rightRotate(18),
$e->bitwise_rightRotate(41)
);
$s1 = $temp[0]->bitwise_xor($temp[1]);
$s1 = $s1->bitwise_xor($temp[2]);
$temp = array(
$e->bitwise_and($f),
$g->bitwise_and($e->bitwise_not())
);
$ch = $temp[0]->bitwise_xor($temp[1]);
$t1 = $h->add($s1);
$t1 = $t1->add($ch);
$t1 = $t1->add($k[$i]);
$t1 = $t1->add($w[$i]);
$h = $g->copy();
$g = $f->copy();
$f = $e->copy();
$e = $d->add($t1);
$d = $c->copy();
$c = $b->copy();
$b = $a->copy();
$a = $t1->add($t2);
}
// Add this chunk's hash to result so far
$hash = array(
$hash[0]->add($a),
$hash[1]->add($b),
$hash[2]->add($c),
$hash[3]->add($d),
$hash[4]->add($e),
$hash[5]->add($f),
$hash[6]->add($g),
$hash[7]->add($h)
);
}
// Produce the final hash value (big-endian)
// (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
$temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
$hash[4]->toBytes() . $hash[5]->toBytes();
if ($this->l != 48) {
$temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
}
return $temp;
}
/**
* Right Rotate
*
* @access private
* @param int $int
* @param int $amt
* @see self::_sha256()
* @return int
*/
function _rightRotate($int, $amt)
{
$invamt = 32 - $amt;
$mask = (1 << $invamt) - 1;
return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
}
/**
* Right Shift
*
* @access private
* @param int $int
* @param int $amt
* @see self::_sha256()
* @return int
*/
function _rightShift($int, $amt)
{
$mask = (1 << (32 - $amt)) - 1;
return ($int >> $amt) & $mask;
}
/**
* Not
*
* @access private
* @param int $int
* @see self::_sha256()
* @return int
*/
function _not($int)
{
return ~$int & 0xFFFFFFFF;
}
/**
* Add
*
* _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
* possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
*
* @param int $...
* @return int
* @see self::_sha256()
* @access private
*/
function _add()
{
static $mod;
if (!isset($mod)) {
$mod = pow(2, 32);
}
$result = 0;
$arguments = func_get_args();
foreach ($arguments as $argument) {
$result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
}
switch (true) {
case is_int($result):
// PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
case version_compare(PHP_VERSION, '5.3.0') >= 0 && (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
// PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
return fmod($result, $mod);
}
return (fmod($result, 0x80000000) & 0x7FFFFFFF) |
((fmod(floor($result / 0x80000000), 2) & 1) << 31);
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
}
================================================
FILE: assets/libraries/phpseclib/Crypt/RC2.php
================================================
* setKey('abcdefgh');
*
* $plaintext = str_repeat('a', 1024);
*
* echo $rc2->decrypt($rc2->encrypt($plaintext));
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_RC2
* @author Patrick Monnerat
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_Base
*
* Base cipher class
*/
if (!class_exists('Crypt_Base')) {
include_once 'Base.php';
}
/**#@+
* @access public
* @see self::encrypt()
* @see self::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_RC2_MODE_CTR', CRYPT_MODE_CTR);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
*/
define('CRYPT_RC2_MODE_ECB', CRYPT_MODE_ECB);
/**
* Encrypt / decrypt using the Code Book Chaining mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_RC2_MODE_CBC', CRYPT_MODE_CBC);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
define('CRYPT_RC2_MODE_CFB', CRYPT_MODE_CFB);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
*/
define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**
* Pure-PHP implementation of RC2.
*
* @package Crypt_RC2
* @access public
*/
class Crypt_RC2 extends Crypt_Base
{
/**
* Block Length of the cipher
*
* @see Crypt_Base::block_size
* @var int
* @access private
*/
var $block_size = 8;
/**
* The Key
*
* @see Crypt_Base::key
* @see self::setKey()
* @var string
* @access private
*/
var $key;
/**
* The Original (unpadded) Key
*
* @see Crypt_Base::key
* @see self::setKey()
* @see self::encrypt()
* @see self::decrypt()
* @var string
* @access private
*/
var $orig_key;
/**
* Don't truncate / null pad key
*
* @see Crypt_Base::_clearBuffers()
* @var bool
* @access private
*/
var $skip_key_adjustment = true;
/**
* Key Length (in bytes)
*
* @see Crypt_RC2::setKeyLength()
* @var int
* @access private
*/
var $key_length = 16; // = 128 bits
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'RC2';
/**
* The mcrypt specific name of the cipher
*
* @see Crypt_Base::cipher_name_mcrypt
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'rc2';
/**
* Optimizing value while CFB-encrypting
*
* @see Crypt_Base::cfb_init_len
* @var int
* @access private
*/
var $cfb_init_len = 500;
/**
* The key length in bits.
*
* @see self::setKeyLength()
* @see self::setKey()
* @var int
* @access private
* @internal Should be in range [1..1024].
* @internal Changing this value after setting the key has no effect.
*/
var $default_key_length = 1024;
/**
* The key length in bits.
*
* @see self::isValidEnine()
* @see self::setKey()
* @var int
* @access private
* @internal Should be in range [1..1024].
*/
var $current_key_length;
/**
* The Key Schedule
*
* @see self::_setupKey()
* @var array
* @access private
*/
var $keys;
/**
* Key expansion randomization table.
* Twice the same 256-value sequence to save a modulus in key expansion.
*
* @see self::setKey()
* @var array
* @access private
*/
var $pitable = array(
0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD,
0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
);
/**
* Inverse key expansion randomization table.
*
* @see self::setKey()
* @var array
* @access private
*/
var $invpitable = array(
0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66,
0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4,
0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20,
0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53,
0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68,
0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B,
0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12,
0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB,
0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3,
0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26,
0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67,
0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB,
0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC,
0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60,
0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7,
0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD,
0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24,
0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31,
0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE,
0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99,
0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C,
0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA,
0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35,
0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61,
0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72,
0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3,
0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F,
0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9,
0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77,
0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75,
0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87,
0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
);
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::Crypt_Base()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
switch ($engine) {
case CRYPT_ENGINE_OPENSSL:
if ($this->current_key_length != 128 || strlen($this->orig_key) < 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'rc2-ecb';
$this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode();
}
return parent::isValidEngine($engine);
}
/**
* Sets the key length.
*
* Valid key lengths are 8 to 1024.
* Calling this function after setting the key has no effect until the next
* Crypt_RC2::setKey() call.
*
* @access public
* @param int $length in bits
*/
function setKeyLength($length)
{
if ($length < 8) {
$this->default_key_length = 1;
} elseif ($length > 1024) {
$this->default_key_length = 128;
} else {
$this->default_key_length = $length;
}
$this->current_key_length = $this->default_key_length;
parent::setKeyLength($length);
}
/**
* Returns the current key length
*
* @access public
* @return int
*/
function getKeyLength()
{
return $this->current_key_length;
}
/**
* Sets the key.
*
* Keys can be of any length. RC2, itself, uses 8 to 1024 bit keys (eg.
* strlen($key) <= 128), however, we only use the first 128 bytes if $key
* has more then 128 bytes in it, and set $key to a single null byte if
* it is empty.
*
* If the key is not explicitly set, it'll be assumed to be a single
* null byte.
*
* @see Crypt_Base::setKey()
* @access public
* @param string $key
* @param int $t1 optional Effective key length in bits.
*/
function setKey($key, $t1 = 0)
{
$this->orig_key = $key;
if ($t1 <= 0) {
$t1 = $this->default_key_length;
} elseif ($t1 > 1024) {
$t1 = 1024;
}
$this->current_key_length = $t1;
// Key byte count should be 1..128.
$key = strlen($key) ? substr($key, 0, 128) : "\x00";
$t = strlen($key);
// The mcrypt RC2 implementation only supports effective key length
// of 1024 bits. It is however possible to handle effective key
// lengths in range 1..1024 by expanding the key and applying
// inverse pitable mapping to the first byte before submitting it
// to mcrypt.
// Key expansion.
$l = array_values(unpack('C*', $key));
$t8 = ($t1 + 7) >> 3;
$tm = 0xFF >> (8 * $t8 - $t1);
// Expand key.
$pitable = $this->pitable;
for ($i = $t; $i < 128; $i++) {
$l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
}
$i = 128 - $t8;
$l[$i] = $pitable[$l[$i] & $tm];
while ($i--) {
$l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
}
// Prepare the key for mcrypt.
$l[0] = $this->invpitable[$l[0]];
array_unshift($l, 'C*');
parent::setKey(call_user_func_array('pack', $l));
}
/**
* Encrypts a message.
*
* Mostly a wrapper for Crypt_Base::encrypt, with some additional OpenSSL handling code
*
* @see self::decrypt()
* @access public
* @param string $plaintext
* @return string $ciphertext
*/
function encrypt($plaintext)
{
if ($this->engine == CRYPT_ENGINE_OPENSSL) {
$temp = $this->key;
$this->key = $this->orig_key;
$result = parent::encrypt($plaintext);
$this->key = $temp;
return $result;
}
return parent::encrypt($plaintext);
}
/**
* Decrypts a message.
*
* Mostly a wrapper for Crypt_Base::decrypt, with some additional OpenSSL handling code
*
* @see self::encrypt()
* @access public
* @param string $ciphertext
* @return string $plaintext
*/
function decrypt($ciphertext)
{
if ($this->engine == CRYPT_ENGINE_OPENSSL) {
$temp = $this->key;
$this->key = $this->orig_key;
$result = parent::decrypt($ciphertext);
$this->key = $temp;
return $result;
}
return parent::decrypt($ciphertext);
}
/**
* Encrypts a block
*
* @see Crypt_Base::_encryptBlock()
* @see Crypt_Base::encrypt()
* @access private
* @param string $in
* @return string
*/
function _encryptBlock($in)
{
list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
$keys = $this->keys;
$limit = 20;
$actions = array($limit => 44, 44 => 64);
$j = 0;
for (;;) {
// Mixing round.
$r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
$r0 |= $r0 >> 16;
$r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
$r1 |= $r1 >> 16;
$r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
$r2 |= $r2 >> 16;
$r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
$r3 |= $r3 >> 16;
if ($j === $limit) {
if ($limit === 64) {
break;
}
// Mashing round.
$r0 += $keys[$r3 & 0x3F];
$r1 += $keys[$r0 & 0x3F];
$r2 += $keys[$r1 & 0x3F];
$r3 += $keys[$r2 & 0x3F];
$limit = $actions[$limit];
}
}
return pack('vvvv', $r0, $r1, $r2, $r3);
}
/**
* Decrypts a block
*
* @see Crypt_Base::_decryptBlock()
* @see Crypt_Base::decrypt()
* @access private
* @param string $in
* @return string
*/
function _decryptBlock($in)
{
list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
$keys = $this->keys;
$limit = 44;
$actions = array($limit => 20, 20 => 0);
$j = 64;
for (;;) {
// R-mixing round.
$r3 = ($r3 | ($r3 << 16)) >> 5;
$r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
$r2 = ($r2 | ($r2 << 16)) >> 3;
$r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
$r1 = ($r1 | ($r1 << 16)) >> 2;
$r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
$r0 = ($r0 | ($r0 << 16)) >> 1;
$r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;
if ($j === $limit) {
if ($limit === 0) {
break;
}
// R-mashing round.
$r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
$r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
$r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
$r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;
$limit = $actions[$limit];
}
}
return pack('vvvv', $r0, $r1, $r2, $r3);
}
/**
* Setup the CRYPT_ENGINE_MCRYPT $engine
*
* @see Crypt_Base::_setupMcrypt()
* @access private
*/
function _setupMcrypt()
{
if (!isset($this->key)) {
$this->setKey('');
}
parent::_setupMcrypt();
}
/**
* Creates the key schedule
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
if (!isset($this->key)) {
$this->setKey('');
}
// Key has already been expanded in Crypt_RC2::setKey():
// Only the first value must be altered.
$l = unpack('Ca/Cb/v*', $this->key);
array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8));
unset($l['a']);
unset($l['b']);
$this->keys = $l;
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* @see Crypt_Base::_setupInlineCrypt()
* @access private
*/
function _setupInlineCrypt()
{
$lambda_functions = &Crypt_RC2::_getLambdaFunctions();
// The first 10 generated $lambda_functions will use the $keys hardcoded as integers
// for the mixing rounds, for better inline crypt performance [~20% faster].
// But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10.
// (Currently, for Crypt_RC2, one generated $lambda_function cost on php5.5@32bit ~60kb unfreeable mem and ~100kb on php5.5@64bit)
$gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
// Generation of a unique hash for our generated code
$code_hash = "Crypt_RC2, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
// Is there a re-usable $lambda_functions in there?
// If not, we have to create it.
if (!isset($lambda_functions[$code_hash])) {
// Init code for both, encrypt and decrypt.
$init_crypt = '$keys = $self->keys;';
switch (true) {
case $gen_hi_opt_code:
$keys = $this->keys;
default:
$keys = array();
foreach ($this->keys as $k => $v) {
$keys[$k] = '$keys[' . $k . ']';
}
}
// $in is the current 8 bytes block which has to be en/decrypt
$encrypt_block = $decrypt_block = '
$in = unpack("v4", $in);
$r0 = $in[1];
$r1 = $in[2];
$r2 = $in[3];
$r3 = $in[4];
';
// Create code for encryption.
$limit = 20;
$actions = array($limit => 44, 44 => 64);
$j = 0;
for (;;) {
// Mixing round.
$encrypt_block .= '
$r0 = (($r0 + ' . $keys[$j++] . ' +
((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
$r0 |= $r0 >> 16;
$r1 = (($r1 + ' . $keys[$j++] . ' +
((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
$r1 |= $r1 >> 16;
$r2 = (($r2 + ' . $keys[$j++] . ' +
((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
$r2 |= $r2 >> 16;
$r3 = (($r3 + ' . $keys[$j++] . ' +
((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
$r3 |= $r3 >> 16;';
if ($j === $limit) {
if ($limit === 64) {
break;
}
// Mashing round.
$encrypt_block .= '
$r0 += $keys[$r3 & 0x3F];
$r1 += $keys[$r0 & 0x3F];
$r2 += $keys[$r1 & 0x3F];
$r3 += $keys[$r2 & 0x3F];';
$limit = $actions[$limit];
}
}
$encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
// Create code for decryption.
$limit = 44;
$actions = array($limit => 20, 20 => 0);
$j = 64;
for (;;) {
// R-mixing round.
$decrypt_block .= '
$r3 = ($r3 | ($r3 << 16)) >> 5;
$r3 = ($r3 - ' . $keys[--$j] . ' -
((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
$r2 = ($r2 | ($r2 << 16)) >> 3;
$r2 = ($r2 - ' . $keys[--$j] . ' -
((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
$r1 = ($r1 | ($r1 << 16)) >> 2;
$r1 = ($r1 - ' . $keys[--$j] . ' -
((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
$r0 = ($r0 | ($r0 << 16)) >> 1;
$r0 = ($r0 - ' . $keys[--$j] . ' -
((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';
if ($j === $limit) {
if ($limit === 0) {
break;
}
// R-mashing round.
$decrypt_block .= '
$r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
$r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
$r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
$r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;';
$limit = $actions[$limit];
}
}
$decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';
// Creates the inline-crypt function
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => $init_crypt,
'encrypt_block' => $encrypt_block,
'decrypt_block' => $decrypt_block
)
);
}
// Set the inline-crypt function as callback in: $this->inline_crypt
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
================================================
FILE: assets/libraries/phpseclib/Crypt/RC4.php
================================================
* setKey('abcdefgh');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $rc4->decrypt($rc4->encrypt($plaintext));
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_RC4
* @author Jim Wigginton
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_Base
*
* Base cipher class
*/
if (!class_exists('Crypt_Base')) {
include_once 'Base.php';
}
/**#@+
* @access private
* @see self::_crypt()
*/
define('CRYPT_RC4_ENCRYPT', 0);
define('CRYPT_RC4_DECRYPT', 1);
/**#@-*/
/**
* Pure-PHP implementation of RC4.
*
* @package Crypt_RC4
* @author Jim Wigginton
* @access public
*/
class Crypt_RC4 extends Crypt_Base
{
/**
* Block Length of the cipher
*
* RC4 is a stream cipher
* so we the block_size to 0
*
* @see Crypt_Base::block_size
* @var int
* @access private
*/
var $block_size = 0;
/**
* Key Length (in bytes)
*
* @see Crypt_RC4::setKeyLength()
* @var int
* @access private
*/
var $key_length = 128; // = 1024 bits
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'RC4';
/**
* The mcrypt specific name of the cipher
*
* @see Crypt_Base::cipher_name_mcrypt
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'arcfour';
/**
* Holds whether performance-optimized $inline_crypt() can/should be used.
*
* @see Crypt_Base::inline_crypt
* @var mixed
* @access private
*/
var $use_inline_crypt = false; // currently not available
/**
* The Key
*
* @see self::setKey()
* @var string
* @access private
*/
var $key;
/**
* The Key Stream for decryption and encryption
*
* @see self::setKey()
* @var array
* @access private
*/
var $stream;
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* @see Crypt_Base::Crypt_Base()
* @return Crypt_RC4
* @access public
*/
function __construct()
{
parent::__construct(CRYPT_MODE_STREAM);
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @access public
*/
function Crypt_RC4()
{
$this->__construct();
}
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::Crypt_Base()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
if ($engine == CRYPT_ENGINE_OPENSSL) {
if (version_compare(PHP_VERSION, '5.3.7') >= 0) {
$this->cipher_name_openssl = 'rc4-40';
} else {
switch (strlen($this->key)) {
case 5:
$this->cipher_name_openssl = 'rc4-40';
break;
case 8:
$this->cipher_name_openssl = 'rc4-64';
break;
case 16:
$this->cipher_name_openssl = 'rc4';
break;
default:
return false;
}
}
}
return parent::isValidEngine($engine);
}
/**
* Dummy function.
*
* Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
* If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
* calling setKey().
*
* [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
* the IV's are relatively easy to predict, an attack described by
* {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
* can be used to quickly guess at the rest of the key. The following links elaborate:
*
* {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
* {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
*
* @param string $iv
* @see self::setKey()
* @access public
*/
function setIV($iv)
{
}
/**
* Sets the key length
*
* Keys can be between 1 and 256 bytes long.
*
* @access public
* @param int $length
*/
function setKeyLength($length)
{
if ($length < 8) {
$this->key_length = 1;
} elseif ($length > 2048) {
$this->key_length = 256;
} else {
$this->key_length = $length >> 3;
}
parent::setKeyLength($length);
}
/**
* Encrypts a message.
*
* @see Crypt_Base::decrypt()
* @see self::_crypt()
* @access public
* @param string $plaintext
* @return string $ciphertext
*/
function encrypt($plaintext)
{
if ($this->engine != CRYPT_ENGINE_INTERNAL) {
return parent::encrypt($plaintext);
}
return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
}
/**
* Decrypts a message.
*
* $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
* At least if the continuous buffer is disabled.
*
* @see Crypt_Base::encrypt()
* @see self::_crypt()
* @access public
* @param string $ciphertext
* @return string $plaintext
*/
function decrypt($ciphertext)
{
if ($this->engine != CRYPT_ENGINE_INTERNAL) {
return parent::decrypt($ciphertext);
}
return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
}
/**
* Setup the key (expansion)
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
$key = $this->key;
$keyLength = strlen($key);
$keyStream = range(0, 255);
$j = 0;
for ($i = 0; $i < 256; $i++) {
$j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
$temp = $keyStream[$i];
$keyStream[$i] = $keyStream[$j];
$keyStream[$j] = $temp;
}
$this->stream = array();
$this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array(
0, // index $i
0, // index $j
$keyStream
);
}
/**
* Encrypts or decrypts a message.
*
* @see self::encrypt()
* @see self::decrypt()
* @access private
* @param string $text
* @param int $mode
* @return string $text
*/
function _crypt($text, $mode)
{
if ($this->changed) {
$this->_setup();
$this->changed = false;
}
$stream = &$this->stream[$mode];
if ($this->continuousBuffer) {
$i = &$stream[0];
$j = &$stream[1];
$keyStream = &$stream[2];
} else {
$i = $stream[0];
$j = $stream[1];
$keyStream = $stream[2];
}
$len = strlen($text);
for ($k = 0; $k < $len; ++$k) {
$i = ($i + 1) & 255;
$ksi = $keyStream[$i];
$j = ($j + $ksi) & 255;
$ksj = $keyStream[$j];
$keyStream[$i] = $ksj;
$keyStream[$j] = $ksi;
$text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
}
return $text;
}
}
================================================
FILE: assets/libraries/phpseclib/Crypt/RSA.php
================================================
* createKey());
*
* $plaintext = 'terrafrost';
*
* $rsa->loadKey($privatekey);
* $ciphertext = $rsa->encrypt($plaintext);
*
* $rsa->loadKey($publickey);
* echo $rsa->decrypt($ciphertext);
* ?>
*
*
* Here's an example of how to create signatures and verify signatures with this library:
*
* createKey());
*
* $plaintext = 'terrafrost';
*
* $rsa->loadKey($privatekey);
* $signature = $rsa->sign($plaintext);
*
* $rsa->loadKey($publickey);
* echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_RSA
* @author Jim Wigginton
* @copyright 2009 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_Random
*/
// the class_exists() will only be called if the crypt_random_string function hasn't been defined and
// will trigger a call to __autoload() if you're wanting to auto-load classes
// call function_exists() a second time to stop the include_once from being called outside
// of the auto loader
if (!function_exists('crypt_random_string')) {
include_once 'Random.php';
}
/**
* Include Crypt_Hash
*/
if (!class_exists('Crypt_Hash')) {
include_once 'Hash.php';
}
/**#@+
* @access public
* @see self::encrypt()
* @see self::decrypt()
*/
/**
* Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
* (OAEP) for encryption / decryption.
*
* Uses sha1 by default.
*
* @see self::setHash()
* @see self::setMGFHash()
*/
define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
/**
* Use PKCS#1 padding.
*
* Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
* compatibility with protocols (like SSH-1) written before OAEP's introduction.
*/
define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
/**
* Do not use any padding
*
* Although this method is not recommended it can none-the-less sometimes be useful if you're trying to decrypt some legacy
* stuff, if you're trying to diagnose why an encrypted message isn't decrypting, etc.
*/
define('CRYPT_RSA_ENCRYPTION_NONE', 3);
/**#@-*/
/**#@+
* @access public
* @see self::sign()
* @see self::verify()
* @see self::setHash()
*/
/**
* Use the Probabilistic Signature Scheme for signing
*
* Uses sha1 by default.
*
* @see self::setSaltLength()
* @see self::setMGFHash()
*/
define('CRYPT_RSA_SIGNATURE_PSS', 1);
/**
* Use the PKCS#1 scheme by default.
*
* Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
* compatibility with protocols (like SSH-2) written before PSS's introduction.
*/
define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
/**#@-*/
/**#@+
* @access private
* @see self::createKey()
*/
/**
* ASN1 Integer
*/
define('CRYPT_RSA_ASN1_INTEGER', 2);
/**
* ASN1 Bit String
*/
define('CRYPT_RSA_ASN1_BITSTRING', 3);
/**
* ASN1 Octet String
*/
define('CRYPT_RSA_ASN1_OCTETSTRING', 4);
/**
* ASN1 Object Identifier
*/
define('CRYPT_RSA_ASN1_OBJECT', 6);
/**
* ASN1 Sequence (with the constucted bit set)
*/
define('CRYPT_RSA_ASN1_SEQUENCE', 48);
/**#@-*/
/**#@+
* @access private
* @see self::Crypt_RSA()
*/
/**
* To use the pure-PHP implementation
*/
define('CRYPT_RSA_MODE_INTERNAL', 1);
/**
* To use the OpenSSL library
*
* (if enabled; otherwise, the internal implementation will be used)
*/
define('CRYPT_RSA_MODE_OPENSSL', 2);
/**#@-*/
/**
* Default openSSL configuration file.
*/
define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
/**#@+
* @access public
* @see self::createKey()
* @see self::setPrivateKeyFormat()
*/
/**
* PKCS#1 formatted private key
*
* Used by OpenSSH
*/
define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
/**
* PuTTY formatted private key
*/
define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
/**
* XML formatted private key
*/
define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
/**
* PKCS#8 formatted private key
*/
define('CRYPT_RSA_PRIVATE_FORMAT_PKCS8', 8);
/**#@-*/
/**#@+
* @access public
* @see self::createKey()
* @see self::setPublicKeyFormat()
*/
/**
* Raw public key
*
* An array containing two Math_BigInteger objects.
*
* The exponent can be indexed with any of the following:
*
* 0, e, exponent, publicExponent
*
* The modulus can be indexed with any of the following:
*
* 1, n, modulo, modulus
*/
define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
/**
* PKCS#1 formatted public key (raw)
*
* Used by File/X509.php
*
* Has the following header:
*
* -----BEGIN RSA PUBLIC KEY-----
*
* Analogous to ssh-keygen's pem format (as specified by -m)
*/
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4);
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
/**
* XML formatted public key
*/
define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
/**
* OpenSSH formatted public key
*
* Place in $HOME/.ssh/authorized_keys
*/
define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
/**
* PKCS#1 formatted public key (encapsulated)
*
* Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
*
* Has the following header:
*
* -----BEGIN PUBLIC KEY-----
*
* Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
* is specific to private keys it's basically creating a DER-encoded wrapper
* for keys. This just extends that same concept to public keys (much like ssh-keygen)
*/
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS8', 7);
/**#@-*/
/**
* Pure-PHP PKCS#1 compliant implementation of RSA.
*
* @package Crypt_RSA
* @author Jim Wigginton
* @access public
*/
class Crypt_RSA
{
/**
* Precomputed Zero
*
* @var Math_BigInteger
* @access private
*/
var $zero;
/**
* Precomputed One
*
* @var Math_BigInteger
* @access private
*/
var $one;
/**
* Private Key Format
*
* @var int
* @access private
*/
var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
/**
* Public Key Format
*
* @var int
* @access public
*/
var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS8;
/**
* Modulus (ie. n)
*
* @var Math_BigInteger
* @access private
*/
var $modulus;
/**
* Modulus length
*
* @var Math_BigInteger
* @access private
*/
var $k;
/**
* Exponent (ie. e or d)
*
* @var Math_BigInteger
* @access private
*/
var $exponent;
/**
* Primes for Chinese Remainder Theorem (ie. p and q)
*
* @var array
* @access private
*/
var $primes;
/**
* Exponents for Chinese Remainder Theorem (ie. dP and dQ)
*
* @var array
* @access private
*/
var $exponents;
/**
* Coefficients for Chinese Remainder Theorem (ie. qInv)
*
* @var array
* @access private
*/
var $coefficients;
/**
* Hash name
*
* @var string
* @access private
*/
var $hashName;
/**
* Hash function
*
* @var Crypt_Hash
* @access private
*/
var $hash;
/**
* Length of hash function output
*
* @var int
* @access private
*/
var $hLen;
/**
* Length of salt
*
* @var int
* @access private
*/
var $sLen;
/**
* Hash function for the Mask Generation Function
*
* @var Crypt_Hash
* @access private
*/
var $mgfHash;
/**
* Length of MGF hash function output
*
* @var int
* @access private
*/
var $mgfHLen;
/**
* Encryption mode
*
* @var int
* @access private
*/
var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
/**
* Signature mode
*
* @var int
* @access private
*/
var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
/**
* Public Exponent
*
* @var mixed
* @access private
*/
var $publicExponent = false;
/**
* Password
*
* @var string
* @access private
*/
var $password = false;
/**
* Components
*
* For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
* because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
*
* @see self::_start_element_handler()
* @var array
* @access private
*/
var $components = array();
/**
* Current String
*
* For use with parsing XML formatted keys.
*
* @see self::_character_handler()
* @see self::_stop_element_handler()
* @var mixed
* @access private
*/
var $current;
/**
* OpenSSL configuration file name.
*
* Set to null to use system configuration file.
* @see self::createKey()
* @var mixed
* @Access public
*/
var $configFile;
/**
* Public key comment field.
*
* @var string
* @access private
*/
var $comment = 'phpseclib-generated-key';
/**
* The constructor
*
* If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
* Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
* openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
*
* @return Crypt_RSA
* @access public
*/
function __construct()
{
if (!class_exists('Math_BigInteger')) {
include_once 'Math/BigInteger.php';
}
$this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
if (!defined('CRYPT_RSA_MODE')) {
switch (true) {
// Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
// Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
// can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
break;
// openssl_pkey_get_details - which is used in the only place Crypt/RSA.php uses OpenSSL - was introduced in PHP 5.2.0
case !function_exists('openssl_pkey_get_details'):
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
break;
case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile):
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
ob_start();
@phpinfo();
$content = ob_get_contents();
ob_end_clean();
preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
$versions = array();
if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) {
$fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
// Remove letter part in OpenSSL version
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
}
}
// it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
switch (true) {
case !isset($versions['Header']):
case !isset($versions['Library']):
case $versions['Header'] == $versions['Library']:
case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
break;
default:
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
}
break;
default:
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
}
}
$this->zero = new Math_BigInteger();
$this->one = new Math_BigInteger(1);
$this->hash = new Crypt_Hash('sha1');
$this->hLen = $this->hash->getLength();
$this->hashName = 'sha1';
$this->mgfHash = new Crypt_Hash('sha1');
$this->mgfHLen = $this->mgfHash->getLength();
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @access public
*/
function Crypt_RSA()
{
$this->__construct();
}
/**
* Create public / private key pair
*
* Returns an array with the following three elements:
* - 'privatekey': The private key.
* - 'publickey': The public key.
* - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
* Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
*
* @access public
* @param int $bits
* @param int $timeout
* @param Math_BigInteger $p
*/
function createKey($bits = 1024, $timeout = false, $partial = array())
{
if (!defined('CRYPT_RSA_EXPONENT')) {
// http://en.wikipedia.org/wiki/65537_%28number%29
define('CRYPT_RSA_EXPONENT', '65537');
}
// per , this number ought not result in primes smaller
// than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
// to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
// CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then
// CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
// generation when there's a chance neither gmp nor OpenSSL are installed)
if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
define('CRYPT_RSA_SMALLEST_PRIME', 4096);
}
// OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
if (CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
$config = array();
if (isset($this->configFile)) {
$config['config'] = $this->configFile;
}
$rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
openssl_pkey_export($rsa, $privatekey, null, $config);
$publickey = openssl_pkey_get_details($rsa);
$publickey = $publickey['key'];
$privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
$publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
// clear the buffer of error strings stemming from a minimalistic openssl.cnf
while (openssl_error_string() !== false) {
}
return array(
'privatekey' => $privatekey,
'publickey' => $publickey,
'partialkey' => false
);
}
static $e;
if (!isset($e)) {
$e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
}
extract($this->_generateMinMax($bits));
$absoluteMin = $min;
$temp = $bits >> 1; // divide by two to see how many bits P and Q would be
if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
$num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
$temp = CRYPT_RSA_SMALLEST_PRIME;
} else {
$num_primes = 2;
}
extract($this->_generateMinMax($temp + $bits % $temp));
$finalMax = $max;
extract($this->_generateMinMax($temp));
$generator = new Math_BigInteger();
$n = $this->one->copy();
if (!empty($partial)) {
extract(unserialize($partial));
} else {
$exponents = $coefficients = $primes = array();
$lcm = array(
'top' => $this->one->copy(),
'bottom' => false
);
}
$start = time();
$i0 = count($primes) + 1;
do {
for ($i = $i0; $i <= $num_primes; $i++) {
if ($timeout !== false) {
$timeout-= time() - $start;
$start = time();
if ($timeout <= 0) {
return array(
'privatekey' => '',
'publickey' => '',
'partialkey' => serialize(array(
'primes' => $primes,
'coefficients' => $coefficients,
'lcm' => $lcm,
'exponents' => $exponents
))
);
}
}
if ($i == $num_primes) {
list($min, $temp) = $absoluteMin->divide($n);
if (!$temp->equals($this->zero)) {
$min = $min->add($this->one); // ie. ceil()
}
$primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
} else {
$primes[$i] = $generator->randomPrime($min, $max, $timeout);
}
if ($primes[$i] === false) { // if we've reached the timeout
if (count($primes) > 1) {
$partialkey = '';
} else {
array_pop($primes);
$partialkey = serialize(array(
'primes' => $primes,
'coefficients' => $coefficients,
'lcm' => $lcm,
'exponents' => $exponents
));
}
return array(
'privatekey' => '',
'publickey' => '',
'partialkey' => $partialkey
);
}
// the first coefficient is calculated differently from the rest
// ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
if ($i > 2) {
$coefficients[$i] = $n->modInverse($primes[$i]);
}
$n = $n->multiply($primes[$i]);
$temp = $primes[$i]->subtract($this->one);
// textbook RSA implementations use Euler's totient function instead of the least common multiple.
// see http://en.wikipedia.org/wiki/Euler%27s_totient_function
$lcm['top'] = $lcm['top']->multiply($temp);
$lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
$exponents[$i] = $e->modInverse($temp);
}
list($temp) = $lcm['top']->divide($lcm['bottom']);
$gcd = $temp->gcd($e);
$i0 = 1;
} while (!$gcd->equals($this->one));
$d = $e->modInverse($temp);
$coefficients[2] = $primes[2]->modInverse($primes[1]);
// from :
// RSAPrivateKey ::= SEQUENCE {
// version Version,
// modulus INTEGER, -- n
// publicExponent INTEGER, -- e
// privateExponent INTEGER, -- d
// prime1 INTEGER, -- p
// prime2 INTEGER, -- q
// exponent1 INTEGER, -- d mod (p-1)
// exponent2 INTEGER, -- d mod (q-1)
// coefficient INTEGER, -- (inverse of q) mod p
// otherPrimeInfos OtherPrimeInfos OPTIONAL
// }
return array(
'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
'publickey' => $this->_convertPublicKey($n, $e),
'partialkey' => false
);
}
/**
* Convert a private key to the appropriate format.
*
* @access private
* @see self::setPrivateKeyFormat()
* @param string $RSAPrivateKey
* @return string
*/
function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
{
$signed = $this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_XML;
$num_primes = count($primes);
$raw = array(
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
'modulus' => $n->toBytes($signed),
'publicExponent' => $e->toBytes($signed),
'privateExponent' => $d->toBytes($signed),
'prime1' => $primes[1]->toBytes($signed),
'prime2' => $primes[2]->toBytes($signed),
'exponent1' => $exponents[1]->toBytes($signed),
'exponent2' => $exponents[2]->toBytes($signed),
'coefficient' => $coefficients[2]->toBytes($signed)
);
// if the format in question does not support multi-prime rsa and multi-prime rsa was used,
// call _convertPublicKey() instead.
switch ($this->privateKeyFormat) {
case CRYPT_RSA_PRIVATE_FORMAT_XML:
if ($num_primes != 2) {
return false;
}
return "\r\n" .
' ' . base64_encode($raw['modulus']) . " \r\n" .
' ' . base64_encode($raw['publicExponent']) . " \r\n" .
' ' . base64_encode($raw['prime1']) . "
\r\n" .
' ' . base64_encode($raw['prime2']) . " \r\n" .
' ' . base64_encode($raw['exponent1']) . " \r\n" .
' ' . base64_encode($raw['exponent2']) . " \r\n" .
' ' . base64_encode($raw['coefficient']) . " \r\n" .
' ' . base64_encode($raw['privateExponent']) . " \r\n" .
' ';
break;
case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
if ($num_primes != 2) {
return false;
}
$key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
$encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
$key.= $encryption;
$key.= "\r\nComment: " . $this->comment . "\r\n";
$public = pack(
'Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($raw['publicExponent']),
$raw['publicExponent'],
strlen($raw['modulus']),
$raw['modulus']
);
$source = pack(
'Na*Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($encryption),
$encryption,
strlen($this->comment),
$this->comment,
strlen($public),
$public
);
$public = base64_encode($public);
$key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
$key.= chunk_split($public, 64);
$private = pack(
'Na*Na*Na*Na*',
strlen($raw['privateExponent']),
$raw['privateExponent'],
strlen($raw['prime1']),
$raw['prime1'],
strlen($raw['prime2']),
$raw['prime2'],
strlen($raw['coefficient']),
$raw['coefficient']
);
if (empty($this->password) && !is_string($this->password)) {
$source.= pack('Na*', strlen($private), $private);
$hashkey = 'putty-private-key-file-mac-key';
} else {
$private.= crypt_random_string(16 - (strlen($private) & 15));
$source.= pack('Na*', strlen($private), $private);
if (!class_exists('Crypt_AES')) {
include_once 'Crypt/AES.php';
}
$sequence = 0;
$symkey = '';
while (strlen($symkey) < 32) {
$temp = pack('Na*', $sequence++, $this->password);
$symkey.= pack('H*', sha1($temp));
}
$symkey = substr($symkey, 0, 32);
$crypto = new Crypt_AES();
$crypto->setKey($symkey);
$crypto->disablePadding();
$private = $crypto->encrypt($private);
$hashkey = 'putty-private-key-file-mac-key' . $this->password;
}
$private = base64_encode($private);
$key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
$key.= chunk_split($private, 64);
if (!class_exists('Crypt_Hash')) {
include_once 'Crypt/Hash.php';
}
$hash = new Crypt_Hash('sha1');
$hash->setKey(pack('H*', sha1($hashkey)));
$key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
return $key;
default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
$components = array();
foreach ($raw as $name => $value) {
$components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
}
$RSAPrivateKey = implode('', $components);
if ($num_primes > 2) {
$OtherPrimeInfos = '';
for ($i = 3; $i <= $num_primes; $i++) {
// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
//
// OtherPrimeInfo ::= SEQUENCE {
// prime INTEGER, -- ri
// exponent INTEGER, -- di
// coefficient INTEGER -- ti
// }
$OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
$OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
$OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
$OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
}
$RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
}
$RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
if ($this->privateKeyFormat == CRYPT_RSA_PRIVATE_FORMAT_PKCS8) {
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$RSAPrivateKey = pack(
'Ca*a*Ca*a*',
CRYPT_RSA_ASN1_INTEGER,
"\01\00",
$rsaOID,
4,
$this->_encodeLength(strlen($RSAPrivateKey)),
$RSAPrivateKey
);
$RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
if (!empty($this->password) || is_string($this->password)) {
$salt = crypt_random_string(8);
$iterationCount = 2048;
if (!class_exists('Crypt_DES')) {
include_once 'Crypt/DES.php';
}
$crypto = new Crypt_DES();
$crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
$RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
$parameters = pack(
'Ca*a*Ca*N',
CRYPT_RSA_ASN1_OCTETSTRING,
$this->_encodeLength(strlen($salt)),
$salt,
CRYPT_RSA_ASN1_INTEGER,
$this->_encodeLength(4),
$iterationCount
);
$pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
$encryptionAlgorithm = pack(
'Ca*a*Ca*a*',
CRYPT_RSA_ASN1_OBJECT,
$this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
$pbeWithMD5AndDES_CBC,
CRYPT_RSA_ASN1_SEQUENCE,
$this->_encodeLength(strlen($parameters)),
$parameters
);
$RSAPrivateKey = pack(
'Ca*a*Ca*a*',
CRYPT_RSA_ASN1_SEQUENCE,
$this->_encodeLength(strlen($encryptionAlgorithm)),
$encryptionAlgorithm,
CRYPT_RSA_ASN1_OCTETSTRING,
$this->_encodeLength(strlen($RSAPrivateKey)),
$RSAPrivateKey
);
$RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
$RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
chunk_split(base64_encode($RSAPrivateKey), 64) .
'-----END ENCRYPTED PRIVATE KEY-----';
} else {
$RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
chunk_split(base64_encode($RSAPrivateKey), 64) .
'-----END PRIVATE KEY-----';
}
return $RSAPrivateKey;
}
if (!empty($this->password) || is_string($this->password)) {
$iv = crypt_random_string(8);
$symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
$symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
if (!class_exists('Crypt_TripleDES')) {
include_once 'Crypt/TripleDES.php';
}
$des = new Crypt_TripleDES();
$des->setKey($symkey);
$des->setIV($iv);
$iv = strtoupper(bin2hex($iv));
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
"Proc-Type: 4,ENCRYPTED\r\n" .
"DEK-Info: DES-EDE3-CBC,$iv\r\n" .
"\r\n" .
chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
'-----END RSA PRIVATE KEY-----';
} else {
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
chunk_split(base64_encode($RSAPrivateKey), 64) .
'-----END RSA PRIVATE KEY-----';
}
return $RSAPrivateKey;
}
}
/**
* Convert a public key to the appropriate format
*
* @access private
* @see self::setPublicKeyFormat()
* @param string $RSAPrivateKey
* @return string
*/
function _convertPublicKey($n, $e)
{
$signed = $this->publicKeyFormat != CRYPT_RSA_PUBLIC_FORMAT_XML;
$modulus = $n->toBytes($signed);
$publicExponent = $e->toBytes($signed);
switch ($this->publicKeyFormat) {
case CRYPT_RSA_PUBLIC_FORMAT_RAW:
return array('e' => $e->copy(), 'n' => $n->copy());
case CRYPT_RSA_PUBLIC_FORMAT_XML:
return "\r\n" .
' ' . base64_encode($modulus) . " \r\n" .
' ' . base64_encode($publicExponent) . " \r\n" .
' ';
break;
case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
// from :
// string "ssh-rsa"
// mpint e
// mpint n
$RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
$RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;
return $RSAPublicKey;
default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1
// from :
// RSAPublicKey ::= SEQUENCE {
// modulus INTEGER, -- n
// publicExponent INTEGER -- e
// }
$components = array(
'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
);
$RSAPublicKey = pack(
'Ca*a*a*',
CRYPT_RSA_ASN1_SEQUENCE,
$this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
$components['modulus'],
$components['publicExponent']
);
if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) {
$RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($RSAPublicKey), 64) .
'-----END RSA PUBLIC KEY-----';
} else {
// sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$RSAPublicKey = chr(0) . $RSAPublicKey;
$RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
$RSAPublicKey = pack(
'Ca*a*',
CRYPT_RSA_ASN1_SEQUENCE,
$this->_encodeLength(strlen($rsaOID . $RSAPublicKey)),
$rsaOID . $RSAPublicKey
);
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($RSAPublicKey), 64) .
'-----END PUBLIC KEY-----';
}
return $RSAPublicKey;
}
}
/**
* Break a public or private key down into its constituant components
*
* @access private
* @see self::_convertPublicKey()
* @see self::_convertPrivateKey()
* @param string $key
* @param int $type
* @return array
*/
function _parseKey($key, $type)
{
if ($type != CRYPT_RSA_PUBLIC_FORMAT_RAW && !is_string($key)) {
return false;
}
switch ($type) {
case CRYPT_RSA_PUBLIC_FORMAT_RAW:
if (!is_array($key)) {
return false;
}
$components = array();
switch (true) {
case isset($key['e']):
$components['publicExponent'] = $key['e']->copy();
break;
case isset($key['exponent']):
$components['publicExponent'] = $key['exponent']->copy();
break;
case isset($key['publicExponent']):
$components['publicExponent'] = $key['publicExponent']->copy();
break;
case isset($key[0]):
$components['publicExponent'] = $key[0]->copy();
}
switch (true) {
case isset($key['n']):
$components['modulus'] = $key['n']->copy();
break;
case isset($key['modulo']):
$components['modulus'] = $key['modulo']->copy();
break;
case isset($key['modulus']):
$components['modulus'] = $key['modulus']->copy();
break;
case isset($key[1]):
$components['modulus'] = $key[1]->copy();
}
return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
case CRYPT_RSA_PRIVATE_FORMAT_PKCS8:
case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
/* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
"outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
http://tools.ietf.org/html/rfc1421#section-4.6.1.1
http://tools.ietf.org/html/rfc1421#section-4.6.1.3
DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
implementation are part of the standard, as well.
* OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
$iv = pack('H*', trim($matches[2]));
$symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
$symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
// remove the Proc-Type / DEK-Info sections as they're no longer needed
$key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
$ciphertext = $this->_extractBER($key);
if ($ciphertext === false) {
$ciphertext = $key;
}
switch ($matches[1]) {
case 'AES-256-CBC':
if (!class_exists('Crypt_AES')) {
include_once 'Crypt/AES.php';
}
$crypto = new Crypt_AES();
break;
case 'AES-128-CBC':
if (!class_exists('Crypt_AES')) {
include_once 'Crypt/AES.php';
}
$symkey = substr($symkey, 0, 16);
$crypto = new Crypt_AES();
break;
case 'DES-EDE3-CFB':
if (!class_exists('Crypt_TripleDES')) {
include_once 'Crypt/TripleDES.php';
}
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
break;
case 'DES-EDE3-CBC':
if (!class_exists('Crypt_TripleDES')) {
include_once 'Crypt/TripleDES.php';
}
$symkey = substr($symkey, 0, 24);
$crypto = new Crypt_TripleDES();
break;
case 'DES-CBC':
if (!class_exists('Crypt_DES')) {
include_once 'Crypt/DES.php';
}
$crypto = new Crypt_DES();
break;
default:
return false;
}
$crypto->setKey($symkey);
$crypto->setIV($iv);
$decoded = $crypto->decrypt($ciphertext);
} else {
$decoded = $this->_extractBER($key);
}
if ($decoded !== false) {
$key = $decoded;
}
$components = array();
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
if ($this->_decodeLength($key) != strlen($key)) {
return false;
}
$tag = ord($this->_string_shift($key));
/* intended for keys for which OpenSSL's asn1parse returns the following:
0:d=0 hl=4 l= 631 cons: SEQUENCE
4:d=1 hl=2 l= 1 prim: INTEGER :00
7:d=1 hl=2 l= 13 cons: SEQUENCE
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
20:d=2 hl=2 l= 0 prim: NULL
22:d=1 hl=4 l= 609 prim: OCTET STRING
ie. PKCS8 keys*/
if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
$this->_string_shift($key, 3);
$tag = CRYPT_RSA_ASN1_SEQUENCE;
}
if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
$temp = $this->_string_shift($key, $this->_decodeLength($key));
if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_OBJECT) {
return false;
}
$length = $this->_decodeLength($temp);
switch ($this->_string_shift($temp, $length)) {
case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
break;
case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
/*
PBEParameter ::= SEQUENCE {
salt OCTET STRING (SIZE(8)),
iterationCount INTEGER }
*/
if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
if ($this->_decodeLength($temp) != strlen($temp)) {
return false;
}
$this->_string_shift($temp); // assume it's an octet string
$salt = $this->_string_shift($temp, $this->_decodeLength($temp));
if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_INTEGER) {
return false;
}
$this->_decodeLength($temp);
list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
$this->_string_shift($key); // assume it's an octet string
$length = $this->_decodeLength($key);
if (strlen($key) != $length) {
return false;
}
if (!class_exists('Crypt_DES')) {
include_once 'Crypt/DES.php';
}
$crypto = new Crypt_DES();
$crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
$key = $crypto->decrypt($key);
if ($key === false) {
return false;
}
return $this->_parseKey($key, CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
default:
return false;
}
/* intended for keys for which OpenSSL's asn1parse returns the following:
0:d=0 hl=4 l= 290 cons: SEQUENCE
4:d=1 hl=2 l= 13 cons: SEQUENCE
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
17:d=2 hl=2 l= 0 prim: NULL
19:d=1 hl=4 l= 271 prim: BIT STRING */
$tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
$this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
// "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
// unused bits in the final subsequent octet. The number shall be in the range zero to seven."
// -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
if ($tag == CRYPT_RSA_ASN1_BITSTRING) {
$this->_string_shift($key);
}
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
if ($this->_decodeLength($key) != strlen($key)) {
return false;
}
$tag = ord($this->_string_shift($key));
}
if ($tag != CRYPT_RSA_ASN1_INTEGER) {
return false;
}
$length = $this->_decodeLength($key);
$temp = $this->_string_shift($key, $length);
if (strlen($temp) != 1 || ord($temp) > 2) {
$components['modulus'] = new Math_BigInteger($temp, 256);
$this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
$length = $this->_decodeLength($key);
$components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
return $components;
}
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
return false;
}
$length = $this->_decodeLength($key);
$components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256));
if (!empty($key)) {
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
$this->_decodeLength($key);
while (!empty($key)) {
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
$this->_decodeLength($key);
$key = substr($key, 1);
$length = $this->_decodeLength($key);
$components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
}
}
return $components;
case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
$parts = explode(' ', $key, 3);
$key = isset($parts[1]) ? base64_decode($parts[1]) : false;
if ($key === false) {
return false;
}
$comment = isset($parts[2]) ? $parts[2] : false;
$cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
if (strlen($key) <= 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
if (strlen($key) <= 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
if ($cleanup && strlen($key)) {
if (strlen($key) <= 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
return strlen($key) ? false : array(
'modulus' => $realModulus,
'publicExponent' => $modulus,
'comment' => $comment
);
} else {
return strlen($key) ? false : array(
'modulus' => $modulus,
'publicExponent' => $publicExponent,
'comment' => $comment
);
}
// http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
// http://en.wikipedia.org/wiki/XML_Signature
case CRYPT_RSA_PRIVATE_FORMAT_XML:
case CRYPT_RSA_PUBLIC_FORMAT_XML:
$this->components = array();
$xml = xml_parser_create('UTF-8');
xml_set_object($xml, $this);
xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
xml_set_character_data_handler($xml, '_data_handler');
// add to account for "dangling" tags like ... that are sometimes added
if (!xml_parse($xml, '' . $key . ' ')) {
xml_parser_free($xml);
unset($xml);
return false;
}
xml_parser_free($xml);
unset($xml);
return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
// from PuTTY's SSHPUBK.C
case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
$components = array();
$key = preg_split('#\r\n|\r|\n#', $key);
$type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
if ($type != 'ssh-rsa') {
return false;
}
$encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
$comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
$publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
$public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
$public = substr($public, 11);
extract(unpack('Nlength', $this->_string_shift($public, 4)));
$components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
extract(unpack('Nlength', $this->_string_shift($public, 4)));
$components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
$privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
$private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
switch ($encryption) {
case 'aes256-cbc':
if (!class_exists('Crypt_AES')) {
include_once 'Crypt/AES.php';
}
$symkey = '';
$sequence = 0;
while (strlen($symkey) < 32) {
$temp = pack('Na*', $sequence++, $this->password);
$symkey.= pack('H*', sha1($temp));
}
$symkey = substr($symkey, 0, 32);
$crypto = new Crypt_AES();
}
if ($encryption != 'none') {
$crypto->setKey($symkey);
$crypto->disablePadding();
$private = $crypto->decrypt($private);
if ($private === false) {
return false;
}
}
extract(unpack('Nlength', $this->_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
extract(unpack('Nlength', $this->_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
extract(unpack('Nlength', $this->_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);
$temp = $components['primes'][1]->subtract($this->one);
$components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
$temp = $components['primes'][2]->subtract($this->one);
$components['exponents'][] = $components['publicExponent']->modInverse($temp);
extract(unpack('Nlength', $this->_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));
return $components;
}
}
/**
* Returns the key size
*
* More specifically, this returns the size of the modulo in bits.
*
* @access public
* @return int
*/
function getSize()
{
return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
}
/**
* Start Element Handler
*
* Called by xml_set_element_handler()
*
* @access private
* @param resource $parser
* @param string $name
* @param array $attribs
*/
function _start_element_handler($parser, $name, $attribs)
{
//$name = strtoupper($name);
switch ($name) {
case 'MODULUS':
$this->current = &$this->components['modulus'];
break;
case 'EXPONENT':
$this->current = &$this->components['publicExponent'];
break;
case 'P':
$this->current = &$this->components['primes'][1];
break;
case 'Q':
$this->current = &$this->components['primes'][2];
break;
case 'DP':
$this->current = &$this->components['exponents'][1];
break;
case 'DQ':
$this->current = &$this->components['exponents'][2];
break;
case 'INVERSEQ':
$this->current = &$this->components['coefficients'][2];
break;
case 'D':
$this->current = &$this->components['privateExponent'];
}
$this->current = '';
}
/**
* Stop Element Handler
*
* Called by xml_set_element_handler()
*
* @access private
* @param resource $parser
* @param string $name
*/
function _stop_element_handler($parser, $name)
{
if (isset($this->current)) {
$this->current = new Math_BigInteger(base64_decode($this->current), 256);
unset($this->current);
}
}
/**
* Data Handler
*
* Called by xml_set_character_data_handler()
*
* @access private
* @param resource $parser
* @param string $data
*/
function _data_handler($parser, $data)
{
if (!isset($this->current) || is_object($this->current)) {
return;
}
$this->current.= trim($data);
}
/**
* Loads a public or private key
*
* Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
*
* @access public
* @param string $key
* @param int $type optional
*/
function loadKey($key, $type = false)
{
if (is_object($key) && strtolower(get_class($key)) == 'crypt_rsa') {
$this->privateKeyFormat = $key->privateKeyFormat;
$this->publicKeyFormat = $key->publicKeyFormat;
$this->k = $key->k;
$this->hLen = $key->hLen;
$this->sLen = $key->sLen;
$this->mgfHLen = $key->mgfHLen;
$this->encryptionMode = $key->encryptionMode;
$this->signatureMode = $key->signatureMode;
$this->password = $key->password;
$this->configFile = $key->configFile;
$this->comment = $key->comment;
if (is_object($key->hash)) {
$this->hash = new Crypt_Hash($key->hash->getHash());
}
if (is_object($key->mgfHash)) {
$this->mgfHash = new Crypt_Hash($key->mgfHash->getHash());
}
if (is_object($key->modulus)) {
$this->modulus = $key->modulus->copy();
}
if (is_object($key->exponent)) {
$this->exponent = $key->exponent->copy();
}
if (is_object($key->publicExponent)) {
$this->publicExponent = $key->publicExponent->copy();
}
$this->primes = array();
$this->exponents = array();
$this->coefficients = array();
foreach ($this->primes as $prime) {
$this->primes[] = $prime->copy();
}
foreach ($this->exponents as $exponent) {
$this->exponents[] = $exponent->copy();
}
foreach ($this->coefficients as $coefficient) {
$this->coefficients[] = $coefficient->copy();
}
return true;
}
if ($type === false) {
$types = array(
CRYPT_RSA_PUBLIC_FORMAT_RAW,
CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
CRYPT_RSA_PRIVATE_FORMAT_XML,
CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
);
foreach ($types as $type) {
$components = $this->_parseKey($key, $type);
if ($components !== false) {
break;
}
}
} else {
$components = $this->_parseKey($key, $type);
}
if ($components === false) {
$this->comment = null;
$this->modulus = null;
$this->k = null;
$this->exponent = null;
$this->primes = null;
$this->exponents = null;
$this->coefficients = null;
$this->publicExponent = null;
return false;
}
if (isset($components['comment']) && $components['comment'] !== false) {
$this->comment = $components['comment'];
}
$this->modulus = $components['modulus'];
$this->k = strlen($this->modulus->toBytes());
$this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
if (isset($components['primes'])) {
$this->primes = $components['primes'];
$this->exponents = $components['exponents'];
$this->coefficients = $components['coefficients'];
$this->publicExponent = $components['publicExponent'];
} else {
$this->primes = array();
$this->exponents = array();
$this->coefficients = array();
$this->publicExponent = false;
}
switch ($type) {
case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
case CRYPT_RSA_PUBLIC_FORMAT_RAW:
$this->setPublicKey();
break;
case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
switch (true) {
case strpos($key, '-BEGIN PUBLIC KEY-') !== false:
case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false:
$this->setPublicKey();
}
}
return true;
}
/**
* Sets the password
*
* Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
* Or rather, pass in $password such that empty($password) && !is_string($password) is true.
*
* @see self::createKey()
* @see self::loadKey()
* @access public
* @param string $password
*/
function setPassword($password = false)
{
$this->password = $password;
}
/**
* Defines the public key
*
* Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
* used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
* message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
* and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
* exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used
* is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being
* public.
*
* Do note that when a new key is loaded the index will be cleared.
*
* Returns true on success, false on failure
*
* @see self::getPublicKey()
* @access public
* @param string $key optional
* @param int $type optional
* @return bool
*/
function setPublicKey($key = false, $type = false)
{
// if a public key has already been loaded return false
if (!empty($this->publicExponent)) {
return false;
}
if ($key === false && !empty($this->modulus)) {
$this->publicExponent = $this->exponent;
return true;
}
if ($type === false) {
$types = array(
CRYPT_RSA_PUBLIC_FORMAT_RAW,
CRYPT_RSA_PUBLIC_FORMAT_PKCS1,
CRYPT_RSA_PUBLIC_FORMAT_XML,
CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
);
foreach ($types as $type) {
$components = $this->_parseKey($key, $type);
if ($components !== false) {
break;
}
}
} else {
$components = $this->_parseKey($key, $type);
}
if ($components === false) {
return false;
}
if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
$this->modulus = $components['modulus'];
$this->exponent = $this->publicExponent = $components['publicExponent'];
return true;
}
$this->publicExponent = $components['publicExponent'];
return true;
}
/**
* Defines the private key
*
* If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force
* phpseclib to treat the key as a private key. This function will do that.
*
* Do note that when a new key is loaded the index will be cleared.
*
* Returns true on success, false on failure
*
* @see self::getPublicKey()
* @access public
* @param string $key optional
* @param int $type optional
* @return bool
*/
function setPrivateKey($key = false, $type = false)
{
if ($key === false && !empty($this->publicExponent)) {
$this->publicExponent = false;
return true;
}
$rsa = new Crypt_RSA();
if (!$rsa->loadKey($key, $type)) {
return false;
}
$rsa->publicExponent = false;
// don't overwrite the old key if the new key is invalid
$this->loadKey($rsa);
return true;
}
/**
* Returns the public key
*
* The public key is only returned under two circumstances - if the private key had the public key embedded within it
* or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
* function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
*
* @see self::getPublicKey()
* @access public
* @param string $key
* @param int $type optional
*/
function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
{
if (empty($this->modulus) || empty($this->publicExponent)) {
return false;
}
$oldFormat = $this->publicKeyFormat;
$this->publicKeyFormat = $type;
$temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
$this->publicKeyFormat = $oldFormat;
return $temp;
}
/**
* Returns the public key's fingerprint
*
* The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is
* no public key currently loaded, false is returned.
* Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716)
*
* @access public
* @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned
* for invalid values.
* @return mixed
*/
function getPublicKeyFingerprint($algorithm = 'md5')
{
if (empty($this->modulus) || empty($this->publicExponent)) {
return false;
}
$modulus = $this->modulus->toBytes(true);
$publicExponent = $this->publicExponent->toBytes(true);
$RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
switch ($algorithm) {
case 'sha256':
$hash = new Crypt_Hash('sha256');
$base = base64_encode($hash->hash($RSAPublicKey));
return substr($base, 0, strlen($base) - 1);
case 'md5':
return substr(chunk_split(md5($RSAPublicKey), 2, ':'), 0, -1);
default:
return false;
}
}
/**
* Returns the private key
*
* The private key is only returned if the currently loaded key contains the constituent prime numbers.
*
* @see self::getPublicKey()
* @access public
* @param string $key
* @param int $type optional
* @return mixed
*/
function getPrivateKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
{
if (empty($this->primes)) {
return false;
}
$oldFormat = $this->privateKeyFormat;
$this->privateKeyFormat = $type;
$temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
$this->privateKeyFormat = $oldFormat;
return $temp;
}
/**
* Returns a minimalistic private key
*
* Returns the private key without the prime number constituants. Structurally identical to a public key that
* hasn't been set as the public key
*
* @see self::getPrivateKey()
* @access private
* @param string $key
* @param int $type optional
*/
function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
{
if (empty($this->modulus) || empty($this->exponent)) {
return false;
}
$oldFormat = $this->publicKeyFormat;
$this->publicKeyFormat = $mode;
$temp = $this->_convertPublicKey($this->modulus, $this->exponent);
$this->publicKeyFormat = $oldFormat;
return $temp;
}
/**
* __toString() magic method
*
* @access public
* @return string
*/
function __toString()
{
$key = $this->getPrivateKey($this->privateKeyFormat);
if ($key !== false) {
return $key;
}
$key = $this->_getPrivatePublicKey($this->publicKeyFormat);
return $key !== false ? $key : '';
}
/**
* __clone() magic method
*
* @access public
* @return Crypt_RSA
*/
function __clone()
{
$key = new Crypt_RSA();
$key->loadKey($this);
return $key;
}
/**
* Generates the smallest and largest numbers requiring $bits bits
*
* @access private
* @param int $bits
* @return array
*/
function _generateMinMax($bits)
{
$bytes = $bits >> 3;
$min = str_repeat(chr(0), $bytes);
$max = str_repeat(chr(0xFF), $bytes);
$msb = $bits & 7;
if ($msb) {
$min = chr(1 << ($msb - 1)) . $min;
$max = chr((1 << $msb) - 1) . $max;
} else {
$min[0] = chr(0x80);
}
return array(
'min' => new Math_BigInteger($min, 256),
'max' => new Math_BigInteger($max, 256)
);
}
/**
* DER-decode the length
*
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
*
* @access private
* @param string $string
* @return int
*/
function _decodeLength(&$string)
{
$length = ord($this->_string_shift($string));
if ($length & 0x80) { // definite length, long form
$length&= 0x7F;
$temp = $this->_string_shift($string, $length);
list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
}
return $length;
}
/**
* DER-encode the length
*
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
*
* @access private
* @param int $length
* @return string
*/
function _encodeLength($length)
{
if ($length <= 0x7F) {
return chr($length);
}
$temp = ltrim(pack('N', $length), chr(0));
return pack('Ca*', 0x80 | strlen($temp), $temp);
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
/**
* Determines the private key format
*
* @see self::createKey()
* @access public
* @param int $format
*/
function setPrivateKeyFormat($format)
{
$this->privateKeyFormat = $format;
}
/**
* Determines the public key format
*
* @see self::createKey()
* @access public
* @param int $format
*/
function setPublicKeyFormat($format)
{
$this->publicKeyFormat = $format;
}
/**
* Determines which hashing function should be used
*
* Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
* decryption. If $hash isn't supported, sha1 is used.
*
* @access public
* @param string $hash
*/
function setHash($hash)
{
// Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
switch ($hash) {
case 'md2':
case 'md5':
case 'sha1':
case 'sha256':
case 'sha384':
case 'sha512':
$this->hash = new Crypt_Hash($hash);
$this->hashName = $hash;
break;
default:
$this->hash = new Crypt_Hash('sha1');
$this->hashName = 'sha1';
}
$this->hLen = $this->hash->getLength();
}
/**
* Determines which hashing function should be used for the mask generation function
*
* The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
* best if Hash and MGFHash are set to the same thing this is not a requirement.
*
* @access public
* @param string $hash
*/
function setMGFHash($hash)
{
// Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
switch ($hash) {
case 'md2':
case 'md5':
case 'sha1':
case 'sha256':
case 'sha384':
case 'sha512':
$this->mgfHash = new Crypt_Hash($hash);
break;
default:
$this->mgfHash = new Crypt_Hash('sha1');
}
$this->mgfHLen = $this->mgfHash->getLength();
}
/**
* Determines the salt length
*
* To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
*
* Typical salt lengths in octets are hLen (the length of the output
* of the hash function Hash) and 0.
*
* @access public
* @param int $format
*/
function setSaltLength($sLen)
{
$this->sLen = $sLen;
}
/**
* Integer-to-Octet-String primitive
*
* See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
*
* @access private
* @param Math_BigInteger $x
* @param int $xLen
* @return string
*/
function _i2osp($x, $xLen)
{
$x = $x->toBytes();
if (strlen($x) > $xLen) {
user_error('Integer too large');
return false;
}
return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
}
/**
* Octet-String-to-Integer primitive
*
* See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
*
* @access private
* @param string $x
* @return Math_BigInteger
*/
function _os2ip($x)
{
return new Math_BigInteger($x, 256);
}
/**
* Exponentiate with or without Chinese Remainder Theorem
*
* See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
*
* @access private
* @param Math_BigInteger $x
* @return Math_BigInteger
*/
function _exponentiate($x)
{
switch (true) {
case empty($this->primes):
case $this->primes[1]->equals($this->zero):
case empty($this->coefficients):
case $this->coefficients[2]->equals($this->zero):
case empty($this->exponents):
case $this->exponents[1]->equals($this->zero):
return $x->modPow($this->exponent, $this->modulus);
}
$num_primes = count($this->primes);
if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
$m_i = array(
1 => $x->modPow($this->exponents[1], $this->primes[1]),
2 => $x->modPow($this->exponents[2], $this->primes[2])
);
$h = $m_i[1]->subtract($m_i[2]);
$h = $h->multiply($this->coefficients[2]);
list(, $h) = $h->divide($this->primes[1]);
$m = $m_i[2]->add($h->multiply($this->primes[2]));
$r = $this->primes[1];
for ($i = 3; $i <= $num_primes; $i++) {
$m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
$r = $r->multiply($this->primes[$i - 1]);
$h = $m_i->subtract($m);
$h = $h->multiply($this->coefficients[$i]);
list(, $h) = $h->divide($this->primes[$i]);
$m = $m->add($r->multiply($h));
}
} else {
$smallest = $this->primes[1];
for ($i = 2; $i <= $num_primes; $i++) {
if ($smallest->compare($this->primes[$i]) > 0) {
$smallest = $this->primes[$i];
}
}
$one = new Math_BigInteger(1);
$r = $one->random($one, $smallest->subtract($one));
$m_i = array(
1 => $this->_blind($x, $r, 1),
2 => $this->_blind($x, $r, 2)
);
$h = $m_i[1]->subtract($m_i[2]);
$h = $h->multiply($this->coefficients[2]);
list(, $h) = $h->divide($this->primes[1]);
$m = $m_i[2]->add($h->multiply($this->primes[2]));
$r = $this->primes[1];
for ($i = 3; $i <= $num_primes; $i++) {
$m_i = $this->_blind($x, $r, $i);
$r = $r->multiply($this->primes[$i - 1]);
$h = $m_i->subtract($m);
$h = $h->multiply($this->coefficients[$i]);
list(, $h) = $h->divide($this->primes[$i]);
$m = $m->add($r->multiply($h));
}
}
return $m;
}
/**
* Performs RSA Blinding
*
* Protects against timing attacks by employing RSA Blinding.
* Returns $x->modPow($this->exponents[$i], $this->primes[$i])
*
* @access private
* @param Math_BigInteger $x
* @param Math_BigInteger $r
* @param int $i
* @return Math_BigInteger
*/
function _blind($x, $r, $i)
{
$x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
$x = $x->modPow($this->exponents[$i], $this->primes[$i]);
$r = $r->modInverse($this->primes[$i]);
$x = $x->multiply($r);
list(, $x) = $x->divide($this->primes[$i]);
return $x;
}
/**
* Performs blinded RSA equality testing
*
* Protects against a particular type of timing attack described.
*
* See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
*
* Thanks for the heads up singpolyma!
*
* @access private
* @param string $x
* @param string $y
* @return bool
*/
function _equals($x, $y)
{
if (strlen($x) != strlen($y)) {
return false;
}
$result = "\0";
$x^= $y;
for ($i = 0; $i < strlen($x); $i++) {
$result|= $x[$i];
}
return $result === "\0";
}
/**
* RSAEP
*
* See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
*
* @access private
* @param Math_BigInteger $m
* @return Math_BigInteger
*/
function _rsaep($m)
{
if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
user_error('Message representative out of range');
return false;
}
return $this->_exponentiate($m);
}
/**
* RSADP
*
* See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
*
* @access private
* @param Math_BigInteger $c
* @return Math_BigInteger
*/
function _rsadp($c)
{
if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
user_error('Ciphertext representative out of range');
return false;
}
return $this->_exponentiate($c);
}
/**
* RSASP1
*
* See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
*
* @access private
* @param Math_BigInteger $m
* @return Math_BigInteger
*/
function _rsasp1($m)
{
if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
user_error('Message representative out of range');
return false;
}
return $this->_exponentiate($m);
}
/**
* RSAVP1
*
* See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
*
* @access private
* @param Math_BigInteger $s
* @return Math_BigInteger
*/
function _rsavp1($s)
{
if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
user_error('Signature representative out of range');
return false;
}
return $this->_exponentiate($s);
}
/**
* MGF1
*
* See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
*
* @access private
* @param string $mgfSeed
* @param int $mgfLen
* @return string
*/
function _mgf1($mgfSeed, $maskLen)
{
// if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
$t = '';
$count = ceil($maskLen / $this->mgfHLen);
for ($i = 0; $i < $count; $i++) {
$c = pack('N', $i);
$t.= $this->mgfHash->hash($mgfSeed . $c);
}
return substr($t, 0, $maskLen);
}
/**
* RSAES-OAEP-ENCRYPT
*
* See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
* {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
*
* @access private
* @param string $m
* @param string $l
* @return string
*/
function _rsaes_oaep_encrypt($m, $l = '')
{
$mLen = strlen($m);
// Length checking
// if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
// be output.
if ($mLen > $this->k - 2 * $this->hLen - 2) {
user_error('Message too long');
return false;
}
// EME-OAEP encoding
$lHash = $this->hash->hash($l);
$ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
$db = $lHash . $ps . chr(1) . $m;
$seed = crypt_random_string($this->hLen);
$dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
$maskedDB = $db ^ $dbMask;
$seedMask = $this->_mgf1($maskedDB, $this->hLen);
$maskedSeed = $seed ^ $seedMask;
$em = chr(0) . $maskedSeed . $maskedDB;
// RSA encryption
$m = $this->_os2ip($em);
$c = $this->_rsaep($m);
$c = $this->_i2osp($c, $this->k);
// Output the ciphertext C
return $c;
}
/**
* RSAES-OAEP-DECRYPT
*
* See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
* messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
*
* Note. Care must be taken to ensure that an opponent cannot
* distinguish the different error conditions in Step 3.g, whether by
* error message or timing, or, more generally, learn partial
* information about the encoded message EM. Otherwise an opponent may
* be able to obtain useful information about the decryption of the
* ciphertext C, leading to a chosen-ciphertext attack such as the one
* observed by Manger [36].
*
* As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
*
* Both the encryption and the decryption operations of RSAES-OAEP take
* the value of a label L as input. In this version of PKCS #1, L is
* the empty string; other uses of the label are outside the scope of
* this document.
*
* @access private
* @param string $c
* @param string $l
* @return string
*/
function _rsaes_oaep_decrypt($c, $l = '')
{
// Length checking
// if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
// be output.
if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
user_error('Decryption error');
return false;
}
// RSA decryption
$c = $this->_os2ip($c);
$m = $this->_rsadp($c);
if ($m === false) {
user_error('Decryption error');
return false;
}
$em = $this->_i2osp($m, $this->k);
// EME-OAEP decoding
$lHash = $this->hash->hash($l);
$y = ord($em[0]);
$maskedSeed = substr($em, 1, $this->hLen);
$maskedDB = substr($em, $this->hLen + 1);
$seedMask = $this->_mgf1($maskedDB, $this->hLen);
$seed = $maskedSeed ^ $seedMask;
$dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
$db = $maskedDB ^ $dbMask;
$lHash2 = substr($db, 0, $this->hLen);
$m = substr($db, $this->hLen);
$hashesMatch = $this->_equals($lHash, $lHash2);
$leadingZeros = 1;
$patternMatch = 0;
$offset = 0;
for ($i = 0; $i < strlen($m); $i++) {
$patternMatch|= $leadingZeros & ($m[$i] === "\1");
$leadingZeros&= $m[$i] === "\0";
$offset+= $patternMatch ? 0 : 1;
}
// we do & instead of && to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation
// to protect against timing attacks
if (!$hashesMatch & !$patternMatch) {
user_error('Decryption error');
return false;
}
// Output the message M
return substr($m, $offset + 1);
}
/**
* Raw Encryption / Decryption
*
* Doesn't use padding and is not recommended.
*
* @access private
* @param string $m
* @return string
*/
function _raw_encrypt($m)
{
$temp = $this->_os2ip($m);
$temp = $this->_rsaep($temp);
return $this->_i2osp($temp, $this->k);
}
/**
* RSAES-PKCS1-V1_5-ENCRYPT
*
* See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
*
* @access private
* @param string $m
* @return string
*/
function _rsaes_pkcs1_v1_5_encrypt($m)
{
$mLen = strlen($m);
// Length checking
if ($mLen > $this->k - 11) {
user_error('Message too long');
return false;
}
// EME-PKCS1-v1_5 encoding
$psLen = $this->k - $mLen - 3;
$ps = '';
while (strlen($ps) != $psLen) {
$temp = crypt_random_string($psLen - strlen($ps));
$temp = str_replace("\x00", '', $temp);
$ps.= $temp;
}
$type = 2;
// see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
$type = 1;
// "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
$ps = str_repeat("\xFF", $psLen);
}
$em = chr(0) . chr($type) . $ps . chr(0) . $m;
// RSA encryption
$m = $this->_os2ip($em);
$c = $this->_rsaep($m);
$c = $this->_i2osp($c, $this->k);
// Output the ciphertext C
return $c;
}
/**
* RSAES-PKCS1-V1_5-DECRYPT
*
* See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
*
* For compatibility purposes, this function departs slightly from the description given in RFC3447.
* The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
* private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
* public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
* to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the
* second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
*
* As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
* with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
* not private key encrypted ciphertext's.
*
* @access private
* @param string $c
* @return string
*/
function _rsaes_pkcs1_v1_5_decrypt($c)
{
// Length checking
if (strlen($c) != $this->k) { // or if k < 11
user_error('Decryption error');
return false;
}
// RSA decryption
$c = $this->_os2ip($c);
$m = $this->_rsadp($c);
if ($m === false) {
user_error('Decryption error');
return false;
}
$em = $this->_i2osp($m, $this->k);
// EME-PKCS1-v1_5 decoding
if (ord($em[0]) != 0 || ord($em[1]) > 2) {
user_error('Decryption error');
return false;
}
$ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
$m = substr($em, strlen($ps) + 3);
if (strlen($ps) < 8) {
user_error('Decryption error');
return false;
}
// Output M
return $m;
}
/**
* EMSA-PSS-ENCODE
*
* See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
*
* @access private
* @param string $m
* @param int $emBits
*/
function _emsa_pss_encode($m, $emBits)
{
// if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
// be output.
$emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
$sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
$mHash = $this->hash->hash($m);
if ($emLen < $this->hLen + $sLen + 2) {
user_error('Encoding error');
return false;
}
$salt = crypt_random_string($sLen);
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
$h = $this->hash->hash($m2);
$ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
$db = $ps . chr(1) . $salt;
$dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
$maskedDB = $db ^ $dbMask;
$maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
$em = $maskedDB . $h . chr(0xBC);
return $em;
}
/**
* EMSA-PSS-VERIFY
*
* See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
*
* @access private
* @param string $m
* @param string $em
* @param int $emBits
* @return string
*/
function _emsa_pss_verify($m, $em, $emBits)
{
// if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
// be output.
$emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
$sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
$mHash = $this->hash->hash($m);
if ($emLen < $this->hLen + $sLen + 2) {
return false;
}
if ($em[strlen($em) - 1] != chr(0xBC)) {
return false;
}
$maskedDB = substr($em, 0, -$this->hLen - 1);
$h = substr($em, -$this->hLen - 1, $this->hLen);
$temp = chr(0xFF << ($emBits & 7));
if ((~$maskedDB[0] & $temp) != $temp) {
return false;
}
$dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
$db = $maskedDB ^ $dbMask;
$db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
$temp = $emLen - $this->hLen - $sLen - 2;
if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
return false;
}
$salt = substr($db, $temp + 1); // should be $sLen long
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
$h2 = $this->hash->hash($m2);
return $this->_equals($h, $h2);
}
/**
* RSASSA-PSS-SIGN
*
* See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
*
* @access private
* @param string $m
* @return string
*/
function _rsassa_pss_sign($m)
{
// EMSA-PSS encoding
$em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
// RSA signature
$m = $this->_os2ip($em);
$s = $this->_rsasp1($m);
$s = $this->_i2osp($s, $this->k);
// Output the signature S
return $s;
}
/**
* RSASSA-PSS-VERIFY
*
* See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
*
* @access private
* @param string $m
* @param string $s
* @return string
*/
function _rsassa_pss_verify($m, $s)
{
// Length checking
if (strlen($s) != $this->k) {
user_error('Invalid signature');
return false;
}
// RSA verification
$modBits = 8 * $this->k;
$s2 = $this->_os2ip($s);
$m2 = $this->_rsavp1($s2);
if ($m2 === false) {
user_error('Invalid signature');
return false;
}
$em = $this->_i2osp($m2, $modBits >> 3);
if ($em === false) {
user_error('Invalid signature');
return false;
}
// EMSA-PSS verification
return $this->_emsa_pss_verify($m, $em, $modBits - 1);
}
/**
* EMSA-PKCS1-V1_5-ENCODE
*
* See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
*
* @access private
* @param string $m
* @param int $emLen
* @return string
*/
function _emsa_pkcs1_v1_5_encode($m, $emLen)
{
$h = $this->hash->hash($m);
if ($h === false) {
return false;
}
// see http://tools.ietf.org/html/rfc3447#page-43
switch ($this->hashName) {
case 'md2':
$t = pack('H*', '3020300c06082a864886f70d020205000410');
break;
case 'md5':
$t = pack('H*', '3020300c06082a864886f70d020505000410');
break;
case 'sha1':
$t = pack('H*', '3021300906052b0e03021a05000414');
break;
case 'sha256':
$t = pack('H*', '3031300d060960864801650304020105000420');
break;
case 'sha384':
$t = pack('H*', '3041300d060960864801650304020205000430');
break;
case 'sha512':
$t = pack('H*', '3051300d060960864801650304020305000440');
}
$t.= $h;
$tLen = strlen($t);
if ($emLen < $tLen + 11) {
user_error('Intended encoded message length too short');
return false;
}
$ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
$em = "\0\1$ps\0$t";
return $em;
}
/**
* RSASSA-PKCS1-V1_5-SIGN
*
* See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
*
* @access private
* @param string $m
* @return string
*/
function _rsassa_pkcs1_v1_5_sign($m)
{
// EMSA-PKCS1-v1_5 encoding
$em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
if ($em === false) {
user_error('RSA modulus too short');
return false;
}
// RSA signature
$m = $this->_os2ip($em);
$s = $this->_rsasp1($m);
$s = $this->_i2osp($s, $this->k);
// Output the signature S
return $s;
}
/**
* RSASSA-PKCS1-V1_5-VERIFY
*
* See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
*
* @access private
* @param string $m
* @return string
*/
function _rsassa_pkcs1_v1_5_verify($m, $s)
{
// Length checking
if (strlen($s) != $this->k) {
user_error('Invalid signature');
return false;
}
// RSA verification
$s = $this->_os2ip($s);
$m2 = $this->_rsavp1($s);
if ($m2 === false) {
user_error('Invalid signature');
return false;
}
$em = $this->_i2osp($m2, $this->k);
if ($em === false) {
user_error('Invalid signature');
return false;
}
// EMSA-PKCS1-v1_5 encoding
$em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
if ($em2 === false) {
user_error('RSA modulus too short');
return false;
}
// Compare
return $this->_equals($em, $em2);
}
/**
* Set Encryption Mode
*
* Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1.
*
* @access public
* @param int $mode
*/
function setEncryptionMode($mode)
{
$this->encryptionMode = $mode;
}
/**
* Set Signature Mode
*
* Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1
*
* @access public
* @param int $mode
*/
function setSignatureMode($mode)
{
$this->signatureMode = $mode;
}
/**
* Set public key comment.
*
* @access public
* @param string $comment
*/
function setComment($comment)
{
$this->comment = $comment;
}
/**
* Get public key comment.
*
* @access public
* @return string
*/
function getComment()
{
return $this->comment;
}
/**
* Encryption
*
* Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
* If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
* be concatenated together.
*
* @see self::decrypt()
* @access public
* @param string $plaintext
* @return string
*/
function encrypt($plaintext)
{
switch ($this->encryptionMode) {
case CRYPT_RSA_ENCRYPTION_NONE:
$plaintext = str_split($plaintext, $this->k);
$ciphertext = '';
foreach ($plaintext as $m) {
$ciphertext.= $this->_raw_encrypt($m);
}
return $ciphertext;
case CRYPT_RSA_ENCRYPTION_PKCS1:
$length = $this->k - 11;
if ($length <= 0) {
return false;
}
$plaintext = str_split($plaintext, $length);
$ciphertext = '';
foreach ($plaintext as $m) {
$ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
}
return $ciphertext;
//case CRYPT_RSA_ENCRYPTION_OAEP:
default:
$length = $this->k - 2 * $this->hLen - 2;
if ($length <= 0) {
return false;
}
$plaintext = str_split($plaintext, $length);
$ciphertext = '';
foreach ($plaintext as $m) {
$ciphertext.= $this->_rsaes_oaep_encrypt($m);
}
return $ciphertext;
}
}
/**
* Decryption
*
* @see self::encrypt()
* @access public
* @param string $plaintext
* @return string
*/
function decrypt($ciphertext)
{
if ($this->k <= 0) {
return false;
}
$ciphertext = str_split($ciphertext, $this->k);
$ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
$plaintext = '';
switch ($this->encryptionMode) {
case CRYPT_RSA_ENCRYPTION_NONE:
$decrypt = '_raw_encrypt';
break;
case CRYPT_RSA_ENCRYPTION_PKCS1:
$decrypt = '_rsaes_pkcs1_v1_5_decrypt';
break;
//case CRYPT_RSA_ENCRYPTION_OAEP:
default:
$decrypt = '_rsaes_oaep_decrypt';
}
foreach ($ciphertext as $c) {
$temp = $this->$decrypt($c);
if ($temp === false) {
return false;
}
$plaintext.= $temp;
}
return $plaintext;
}
/**
* Create a signature
*
* @see self::verify()
* @access public
* @param string $message
* @return string
*/
function sign($message)
{
if (empty($this->modulus) || empty($this->exponent)) {
return false;
}
switch ($this->signatureMode) {
case CRYPT_RSA_SIGNATURE_PKCS1:
return $this->_rsassa_pkcs1_v1_5_sign($message);
//case CRYPT_RSA_SIGNATURE_PSS:
default:
return $this->_rsassa_pss_sign($message);
}
}
/**
* Verifies a signature
*
* @see self::sign()
* @access public
* @param string $message
* @param string $signature
* @return bool
*/
function verify($message, $signature)
{
if (empty($this->modulus) || empty($this->exponent)) {
return false;
}
switch ($this->signatureMode) {
case CRYPT_RSA_SIGNATURE_PKCS1:
return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
//case CRYPT_RSA_SIGNATURE_PSS:
default:
return $this->_rsassa_pss_verify($message, $signature);
}
}
/**
* Extract raw BER from Base64 encoding
*
* @access private
* @param string $str
* @return string
*/
function _extractBER($str)
{
/* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
* above and beyond the ceritificate.
* ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
*
* Bag Attributes
* localKeyID: 01 00 00 00
* subject=/O=organization/OU=org unit/CN=common name
* issuer=/O=organization/CN=common name
*/
$temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
// remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
$temp = preg_replace('#-+[^-]+-+#', '', $temp);
// remove new lines
$temp = str_replace(array("\r", "\n", ' '), '', $temp);
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
return $temp != false ? $temp : $str;
}
}
================================================
FILE: assets/libraries/phpseclib/Crypt/Random.php
================================================
*
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_Random
* @author Jim Wigginton
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
// laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently,
// have phpseclib as a requirement as well. if you're developing such a program you may encounter
// a "Cannot redeclare crypt_random_string()" error.
if (!function_exists('crypt_random_string')) {
/**
* "Is Windows" test
*
* @access private
*/
define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
/**
* Generate a random string.
*
* Although microoptimizations are generally discouraged as they impair readability this function is ripe with
* microoptimizations because this function has the potential of being called a huge number of times.
* eg. for RSA key generation.
*
* @param int $length
* @return string
* @access public
*/
function crypt_random_string($length)
{
if (!$length) {
return '';
}
if (CRYPT_RANDOM_IS_WINDOWS) {
// method 1. prior to PHP 5.3, mcrypt_create_iv() would call rand() on windows
if (extension_loaded('mcrypt') && version_compare(PHP_VERSION, '5.3.0', '>=')) {
return @mcrypt_create_iv($length);
}
// method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
// to quote , "possible blocking behavior". as of 5.3.4
// openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
// call php_win32_get_random_bytes():
//
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
//
// php_win32_get_random_bytes() is defined thusly:
//
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
//
// we're calling it, all the same, in the off chance that the mcrypt extension is not available
if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
return openssl_random_pseudo_bytes($length);
}
} else {
// method 1. the fastest
if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.0', '>=')) {
return openssl_random_pseudo_bytes($length);
}
// method 2
static $fp = true;
if ($fp === true) {
// warning's will be output unles the error suppression operator is used. errors such as
// "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
$fp = @fopen('/dev/urandom', 'rb');
}
if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
return fread($fp, $length);
}
// method 3. pretty much does the same thing as method 2 per the following url:
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
// surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
// not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
// restrictions or some such
if (extension_loaded('mcrypt')) {
return @mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
}
}
// at this point we have no choice but to use a pure-PHP CSPRNG
// cascade entropy across multiple PHP instances by fixing the session and collecting all
// environmental variables, including the previous session data and the current session
// data.
//
// mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
// easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
// PHP isn't low level to be able to use those as sources and on a web server there's not likely
// going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
// however, a ton of people visiting the website. obviously you don't want to base your seeding
// soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
// by the user and (2) this isn't just looking at the data sent by the current user - it's based
// on the data sent by all users. one user requests the page and a hash of their info is saved.
// another user visits the page and the serialization of their data is utilized along with the
// server envirnment stuff and a hash of the previous http request data (which itself utilizes
// a hash of the session data before that). certainly an attacker should be assumed to have
// full control over his own http requests. he, however, is not going to have control over
// everyone's http requests.
static $crypto = false, $v;
if ($crypto === false) {
// save old session data
$old_session_id = session_id();
$old_use_cookies = ini_get('session.use_cookies');
$old_session_cache_limiter = session_cache_limiter();
$_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
if ($old_session_id != '') {
session_write_close();
}
session_id(1);
ini_set('session.use_cookies', 0);
session_cache_limiter('');
session_start();
$v = $seed = $_SESSION['seed'] = pack('H*', sha1(
(isset($_SERVER) ? phpseclib_safe_serialize($_SERVER) : '') .
(isset($_POST) ? phpseclib_safe_serialize($_POST) : '') .
(isset($_GET) ? phpseclib_safe_serialize($_GET) : '') .
(isset($_COOKIE) ? phpseclib_safe_serialize($_COOKIE) : '') .
phpseclib_safe_serialize($GLOBALS) .
phpseclib_safe_serialize($_SESSION) .
phpseclib_safe_serialize($_OLD_SESSION)
));
if (!isset($_SESSION['count'])) {
$_SESSION['count'] = 0;
}
$_SESSION['count']++;
session_write_close();
// restore old session data
if ($old_session_id != '') {
session_id($old_session_id);
session_start();
ini_set('session.use_cookies', $old_use_cookies);
session_cache_limiter($old_session_cache_limiter);
} else {
if ($_OLD_SESSION !== false) {
$_SESSION = $_OLD_SESSION;
unset($_OLD_SESSION);
} else {
unset($_SESSION);
}
}
// in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
// the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
// if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
// original hash and the current hash. we'll be emulating that. for more info see the following URL:
//
// http://tools.ietf.org/html/rfc4253#section-7.2
//
// see the is_string($crypto) part for an example of how to expand the keys
$key = pack('H*', sha1($seed . 'A'));
$iv = pack('H*', sha1($seed . 'C'));
// ciphers are used as per the nist.gov link below. also, see this link:
//
// http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
switch (true) {
case phpseclib_resolve_include_path('Crypt/AES.php'):
if (!class_exists('Crypt_AES')) {
include_once 'AES.php';
}
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
break;
case phpseclib_resolve_include_path('Crypt/Twofish.php'):
if (!class_exists('Crypt_Twofish')) {
include_once 'Twofish.php';
}
$crypto = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
break;
case phpseclib_resolve_include_path('Crypt/Blowfish.php'):
if (!class_exists('Crypt_Blowfish')) {
include_once 'Blowfish.php';
}
$crypto = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
break;
case phpseclib_resolve_include_path('Crypt/TripleDES.php'):
if (!class_exists('Crypt_TripleDES')) {
include_once 'TripleDES.php';
}
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
break;
case phpseclib_resolve_include_path('Crypt/DES.php'):
if (!class_exists('Crypt_DES')) {
include_once 'DES.php';
}
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
break;
case phpseclib_resolve_include_path('Crypt/RC4.php'):
if (!class_exists('Crypt_RC4')) {
include_once 'RC4.php';
}
$crypto = new Crypt_RC4();
break;
default:
user_error('crypt_random_string requires at least one symmetric cipher be loaded');
return false;
}
$crypto->setKey($key);
$crypto->setIV($iv);
$crypto->enableContinuousBuffer();
}
//return $crypto->encrypt(str_repeat("\0", $length));
// the following is based off of ANSI X9.31:
//
// http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
//
// OpenSSL uses that same standard for it's random numbers:
//
// http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
// (do a search for "ANS X9.31 A.2.4")
$result = '';
while (strlen($result) < $length) {
$i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
$r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
$v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
$result.= $r;
}
return substr($result, 0, $length);
}
}
if (!function_exists('phpseclib_safe_serialize')) {
/**
* Safely serialize variables
*
* If a class has a private __sleep() method it'll give a fatal error on PHP 5.2 and earlier.
* PHP 5.3 will emit a warning.
*
* @param mixed $arr
* @access public
*/
function phpseclib_safe_serialize(&$arr)
{
if (is_object($arr)) {
return '';
}
if (!is_array($arr)) {
return serialize($arr);
}
// prevent circular array recursion
if (isset($arr['__phpseclib_marker'])) {
return '';
}
$safearr = array();
$arr['__phpseclib_marker'] = true;
foreach (array_keys($arr) as $key) {
// do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
if ($key !== '__phpseclib_marker') {
$safearr[$key] = phpseclib_safe_serialize($arr[$key]);
}
}
unset($arr['__phpseclib_marker']);
return serialize($safearr);
}
}
if (!function_exists('phpseclib_resolve_include_path')) {
/**
* Resolve filename against the include path.
*
* Wrapper around stream_resolve_include_path() (which was introduced in
* PHP 5.3.2) with fallback implementation for earlier PHP versions.
*
* @param string $filename
* @return string|false
* @access public
*/
function phpseclib_resolve_include_path($filename)
{
if (function_exists('stream_resolve_include_path')) {
return stream_resolve_include_path($filename);
}
// handle non-relative paths
if (file_exists($filename)) {
return realpath($filename);
}
$paths = PATH_SEPARATOR == ':' ?
preg_split('#(?
* setKey('abcdefghijklmnop');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $rijndael->decrypt($rijndael->encrypt($plaintext));
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_Rijndael
* @author Jim Wigginton
* @copyright 2008 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_Base
*
* Base cipher class
*/
if (!class_exists('Crypt_Base')) {
include_once 'Base.php';
}
/**#@+
* @access public
* @see self::encrypt()
* @see self::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_RIJNDAEL_MODE_CTR', CRYPT_MODE_CTR);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
*/
define('CRYPT_RIJNDAEL_MODE_ECB', CRYPT_MODE_ECB);
/**
* Encrypt / decrypt using the Code Book Chaining mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_RIJNDAEL_MODE_CBC', CRYPT_MODE_CBC);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
define('CRYPT_RIJNDAEL_MODE_CFB', CRYPT_MODE_CFB);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
*/
define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**
* Pure-PHP implementation of Rijndael.
*
* @package Crypt_Rijndael
* @author Jim Wigginton
* @access public
*/
class Crypt_Rijndael extends Crypt_Base
{
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'RIJNDAEL';
/**
* The mcrypt specific name of the cipher
*
* Mcrypt is useable for 128/192/256-bit $block_size/$key_length. For 160/224 not.
* Crypt_Rijndael determines automatically whether mcrypt is useable
* or not for the current $block_size/$key_length.
* In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly.
*
* @see Crypt_Base::cipher_name_mcrypt
* @see Crypt_Base::engine
* @see self::isValidEngine()
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'rijndael-128';
/**
* The default salt used by setPassword()
*
* @see Crypt_Base::password_default_salt
* @see Crypt_Base::setPassword()
* @var string
* @access private
*/
var $password_default_salt = 'phpseclib';
/**
* The Key Schedule
*
* @see self::_setup()
* @var array
* @access private
*/
var $w;
/**
* The Inverse Key Schedule
*
* @see self::_setup()
* @var array
* @access private
*/
var $dw;
/**
* The Block Length divided by 32
*
* @see self::setBlockLength()
* @var int
* @access private
* @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
* because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
* derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
* of that, we'll just precompute it once.
*/
var $Nb = 4;
/**
* The Key Length (in bytes)
*
* @see self::setKeyLength()
* @var int
* @access private
* @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
* because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
* derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
* of that, we'll just precompute it once.
*/
var $key_length = 16;
/**
* The Key Length divided by 32
*
* @see self::setKeyLength()
* @var int
* @access private
* @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
*/
var $Nk = 4;
/**
* The Number of Rounds
*
* @var int
* @access private
* @internal The max value is 14, the min value is 10.
*/
var $Nr;
/**
* Shift offsets
*
* @var array
* @access private
*/
var $c;
/**
* Holds the last used key- and block_size information
*
* @var array
* @access private
*/
var $kl;
/**
* Sets the key.
*
* Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
* whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length
* up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the
* excess bits.
*
* If the key is not explicitly set, it'll be assumed to be all null bytes.
*
* Note: 160/224-bit keys must explicitly set by setKeyLength(), otherwise they will be round/pad up to 192/256 bits.
*
* @see Crypt_Base:setKey()
* @see self::setKeyLength()
* @access public
* @param string $key
*/
function setKey($key)
{
if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_size = 16;
break;
case $length <= 20:
$this->key_size = 20;
break;
case $length <= 24:
$this->key_size = 24;
break;
case $length <= 28:
$this->key_size = 28;
break;
default:
$this->key_size = 32;
}
}
parent::setKey($key);
}
/**
* Sets the key length
*
* Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
*
* Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
* and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
* 192/256 bits as, for example, mcrypt will do.
*
* That said, if you want be compatible with other Rijndael and AES implementations,
* you should not setKeyLength(160) or setKeyLength(224).
*
* Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use
* the mcrypt php extension, even if available.
* This results then in slower encryption.
*
* @access public
* @param int $length
*/
function setKeyLength($length)
{
switch (true) {
case $length <= 128:
$this->key_length = 16;
break;
case $length <= 160:
$this->key_length = 20;
break;
case $length <= 192:
$this->key_length = 24;
break;
case $length <= 224:
$this->key_length = 28;
break;
default:
$this->key_length = 32;
}
parent::setKeyLength($length);
}
/**
* Sets the block length
*
* Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
*
* @access public
* @param int $length
*/
function setBlockLength($length)
{
$length >>= 5;
if ($length > 8) {
$length = 8;
} elseif ($length < 4) {
$length = 4;
}
$this->Nb = $length;
$this->block_size = $length << 2;
$this->changed = true;
$this->_setEngine();
}
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::Crypt_Base()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
switch ($engine) {
case CRYPT_ENGINE_OPENSSL:
if ($this->block_size != 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb';
$this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->_openssl_translate_mode();
break;
case CRYPT_ENGINE_MCRYPT:
$this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
if ($this->key_length % 8) { // is it a 160/224-bit key?
// mcrypt is not usable for them, only for 128/192/256-bit keys
return false;
}
}
return parent::isValidEngine($engine);
}
/**
* Encrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _encryptBlock($in)
{
static $tables;
if (empty($tables)) {
$tables = &$this->_getTables();
}
$t0 = $tables[0];
$t1 = $tables[1];
$t2 = $tables[2];
$t3 = $tables[3];
$sbox = $tables[4];
$state = array();
$words = unpack('N*', $in);
$c = $this->c;
$w = $this->w;
$Nb = $this->Nb;
$Nr = $this->Nr;
// addRoundKey
$wc = $Nb - 1;
foreach ($words as $word) {
$state[] = $word ^ $w[++$wc];
}
// fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
// subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
// Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
// Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
// Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
// equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
// [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
$temp = array();
for ($round = 1; $round < $Nr; ++$round) {
$i = 0; // $c[0] == 0
$j = $c[1];
$k = $c[2];
$l = $c[3];
while ($i < $Nb) {
$temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
$t1[$state[$j] >> 16 & 0x000000FF] ^
$t2[$state[$k] >> 8 & 0x000000FF] ^
$t3[$state[$l] & 0x000000FF] ^
$w[++$wc];
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
$state = $temp;
}
// subWord
for ($i = 0; $i < $Nb; ++$i) {
$state[$i] = $sbox[$state[$i] & 0x000000FF] |
($sbox[$state[$i] >> 8 & 0x000000FF] << 8) |
($sbox[$state[$i] >> 16 & 0x000000FF] << 16) |
($sbox[$state[$i] >> 24 & 0x000000FF] << 24);
}
// shiftRows + addRoundKey
$i = 0; // $c[0] == 0
$j = $c[1];
$k = $c[2];
$l = $c[3];
while ($i < $Nb) {
$temp[$i] = ($state[$i] & 0xFF000000) ^
($state[$j] & 0x00FF0000) ^
($state[$k] & 0x0000FF00) ^
($state[$l] & 0x000000FF) ^
$w[$i];
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
switch ($Nb) {
case 8:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
case 7:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
case 6:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
case 5:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
default:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
}
}
/**
* Decrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _decryptBlock($in)
{
static $invtables;
if (empty($invtables)) {
$invtables = &$this->_getInvTables();
}
$dt0 = $invtables[0];
$dt1 = $invtables[1];
$dt2 = $invtables[2];
$dt3 = $invtables[3];
$isbox = $invtables[4];
$state = array();
$words = unpack('N*', $in);
$c = $this->c;
$dw = $this->dw;
$Nb = $this->Nb;
$Nr = $this->Nr;
// addRoundKey
$wc = $Nb - 1;
foreach ($words as $word) {
$state[] = $word ^ $dw[++$wc];
}
$temp = array();
for ($round = $Nr - 1; $round > 0; --$round) {
$i = 0; // $c[0] == 0
$j = $Nb - $c[1];
$k = $Nb - $c[2];
$l = $Nb - $c[3];
while ($i < $Nb) {
$temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
$dt1[$state[$j] >> 16 & 0x000000FF] ^
$dt2[$state[$k] >> 8 & 0x000000FF] ^
$dt3[$state[$l] & 0x000000FF] ^
$dw[++$wc];
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
$state = $temp;
}
// invShiftRows + invSubWord + addRoundKey
$i = 0; // $c[0] == 0
$j = $Nb - $c[1];
$k = $Nb - $c[2];
$l = $Nb - $c[3];
while ($i < $Nb) {
$word = ($state[$i] & 0xFF000000) |
($state[$j] & 0x00FF0000) |
($state[$k] & 0x0000FF00) |
($state[$l] & 0x000000FF);
$temp[$i] = $dw[$i] ^ ($isbox[$word & 0x000000FF] |
($isbox[$word >> 8 & 0x000000FF] << 8) |
($isbox[$word >> 16 & 0x000000FF] << 16) |
($isbox[$word >> 24 & 0x000000FF] << 24));
++$i;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
switch ($Nb) {
case 8:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
case 7:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
case 6:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
case 5:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
default:
return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
}
}
/**
* Setup the key (expansion)
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
// Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
// See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
static $rcon = array(0,
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
);
if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) {
// already expanded
return;
}
$this->kl = array('key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size);
$this->Nk = $this->key_length >> 2;
// see Rijndael-ammended.pdf#page=44
$this->Nr = max($this->Nk, $this->Nb) + 6;
// shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
// "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
// shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
// "Table 2: Shift offsets for different block lengths"
switch ($this->Nb) {
case 4:
case 5:
case 6:
$this->c = array(0, 1, 2, 3);
break;
case 7:
$this->c = array(0, 1, 2, 4);
break;
case 8:
$this->c = array(0, 1, 3, 4);
}
$w = array_values(unpack('N*words', $this->key));
$length = $this->Nb * ($this->Nr + 1);
for ($i = $this->Nk; $i < $length; $i++) {
$temp = $w[$i - 1];
if ($i % $this->Nk == 0) {
// according to , "the size of an integer is platform-dependent".
// on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
// 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
// with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
$temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
$temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
} elseif ($this->Nk > 6 && $i % $this->Nk == 4) {
$temp = $this->_subWord($temp);
}
$w[$i] = $w[$i - $this->Nk] ^ $temp;
}
// convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
// and generate the inverse key schedule. more specifically,
// according to (section 5.3.3),
// "The key expansion for the Inverse Cipher is defined as follows:
// 1. Apply the Key Expansion.
// 2. Apply InvMixColumn to all Round Keys except the first and the last one."
// also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
list($dt0, $dt1, $dt2, $dt3) = $this->_getInvTables();
$temp = $this->w = $this->dw = array();
for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
if ($col == $this->Nb) {
if ($row == 0) {
$this->dw[0] = $this->w[0];
} else {
// subWord + invMixColumn + invSubWord = invMixColumn
$j = 0;
while ($j < $this->Nb) {
$dw = $this->_subWord($this->w[$row][$j]);
$temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^
$dt1[$dw >> 16 & 0x000000FF] ^
$dt2[$dw >> 8 & 0x000000FF] ^
$dt3[$dw & 0x000000FF];
$j++;
}
$this->dw[$row] = $temp;
}
$col = 0;
$row++;
}
$this->w[$row][$col] = $w[$i];
}
$this->dw[$row] = $this->w[$row];
// Converting to 1-dim key arrays (both ascending)
$this->dw = array_reverse($this->dw);
$w = array_pop($this->w);
$dw = array_pop($this->dw);
foreach ($this->w as $r => $wr) {
foreach ($wr as $c => $wc) {
$w[] = $wc;
$dw[] = $this->dw[$r][$c];
}
}
$this->w = $w;
$this->dw = $dw;
}
/**
* Performs S-Box substitutions
*
* @access private
* @param int $word
*/
function _subWord($word)
{
static $sbox;
if (empty($sbox)) {
list(, , , , $sbox) = $this->_getTables();
}
return $sbox[$word & 0x000000FF] |
($sbox[$word >> 8 & 0x000000FF] << 8) |
($sbox[$word >> 16 & 0x000000FF] << 16) |
($sbox[$word >> 24 & 0x000000FF] << 24);
}
/**
* Provides the mixColumns and sboxes tables
*
* @see Crypt_Rijndael:_encryptBlock()
* @see Crypt_Rijndael:_setupInlineCrypt()
* @see Crypt_Rijndael:_subWord()
* @access private
* @return array &$tables
*/
function &_getTables()
{
static $tables;
if (empty($tables)) {
// according to (section 5.2.1),
// precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
// those are the names we'll use.
$t3 = array_map('intval', array(
// with array_map('intval', ...) we ensure we have only int's and not
// some slower floats converted by php automatically on high values
0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
));
foreach ($t3 as $t3i) {
$t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >> 8) & 0x00FFFFFF);
$t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF);
$t2[] = (($t3i << 8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF);
}
$tables = array(
// The Precomputed mixColumns tables t0 - t3
$t0,
$t1,
$t2,
$t3,
// The SubByte S-Box
array(
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
)
);
}
return $tables;
}
/**
* Provides the inverse mixColumns and inverse sboxes tables
*
* @see Crypt_Rijndael:_decryptBlock()
* @see Crypt_Rijndael:_setupInlineCrypt()
* @see Crypt_Rijndael:_setupKey()
* @access private
* @return array &$tables
*/
function &_getInvTables()
{
static $tables;
if (empty($tables)) {
$dt3 = array_map('intval', array(
0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
));
foreach ($dt3 as $dt3i) {
$dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF);
$dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF);
$dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF);
};
$tables = array(
// The Precomputed inverse mixColumns tables dt0 - dt3
$dt0,
$dt1,
$dt2,
$dt3,
// The inverse SubByte S-Box
array(
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
)
);
}
return $tables;
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* @see Crypt_Base::_setupInlineCrypt()
* @access private
*/
function _setupInlineCrypt()
{
// Note: _setupInlineCrypt() will be called only if $this->changed === true
// So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt().
// However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible.
$lambda_functions =& Crypt_Rijndael::_getLambdaFunctions();
// We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
// (Currently, for Crypt_Rijndael/AES, one generated $lambda_function cost on php5.5@32bit ~80kb unfreeable mem and ~130kb on php5.5@64bit)
// After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
$gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
// Generation of a uniqe hash for our generated code
$code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
if (!isset($lambda_functions[$code_hash])) {
switch (true) {
case $gen_hi_opt_code:
// The hi-optimized $lambda_functions will use the key-words hardcoded for better performance.
$w = $this->w;
$dw = $this->dw;
$init_encrypt = '';
$init_decrypt = '';
break;
default:
for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) {
$w[] = '$w[' . $i . ']';
$dw[] = '$dw[' . $i . ']';
}
$init_encrypt = '$w = $self->w;';
$init_decrypt = '$dw = $self->dw;';
}
$Nr = $this->Nr;
$Nb = $this->Nb;
$c = $this->c;
// Generating encrypt code:
$init_encrypt.= '
static $tables;
if (empty($tables)) {
$tables = &$self->_getTables();
}
$t0 = $tables[0];
$t1 = $tables[1];
$t2 = $tables[2];
$t3 = $tables[3];
$sbox = $tables[4];
';
$s = 'e';
$e = 's';
$wc = $Nb - 1;
// Preround: addRoundKey
$encrypt_block = '$in = unpack("N*", $in);'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n";
}
// Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
for ($round = 1; $round < $Nr; ++$round) {
list($s, $e) = array($e, $s);
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block.=
'$'.$e.$i.' =
$t0[($'.$s.$i .' >> 24) & 0xff] ^
$t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^
$t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^
$t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^
'.$w[++$wc].";\n";
}
}
// Finalround: subWord + shiftRows + addRoundKey
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block.=
'$'.$e.$i.' =
$sbox[ $'.$e.$i.' & 0xff] |
($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
}
$encrypt_block .= '$in = pack("N*"'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$encrypt_block.= ',
($'.$e.$i .' & '.((int)0xFF000000).') ^
($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000 ) ^
($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00 ) ^
($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF ) ^
'.$w[$i]."\n";
}
$encrypt_block .= ');';
// Generating decrypt code:
$init_decrypt.= '
static $invtables;
if (empty($invtables)) {
$invtables = &$self->_getInvTables();
}
$dt0 = $invtables[0];
$dt1 = $invtables[1];
$dt2 = $invtables[2];
$dt3 = $invtables[3];
$isbox = $invtables[4];
';
$s = 'e';
$e = 's';
$wc = $Nb - 1;
// Preround: addRoundKey
$decrypt_block = '$in = unpack("N*", $in);'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n";
}
// Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
for ($round = 1; $round < $Nr; ++$round) {
list($s, $e) = array($e, $s);
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block.=
'$'.$e.$i.' =
$dt0[($'.$s.$i .' >> 24) & 0xff] ^
$dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^
$dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^
$dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^
'.$dw[++$wc].";\n";
}
}
// Finalround: subWord + shiftRows + addRoundKey
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block.=
'$'.$e.$i.' =
$isbox[ $'.$e.$i.' & 0xff] |
($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
}
$decrypt_block .= '$in = pack("N*"'."\n";
for ($i = 0; $i < $Nb; ++$i) {
$decrypt_block.= ',
($'.$e.$i. ' & '.((int)0xFF000000).') ^
($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000 ) ^
($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00 ) ^
($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF ) ^
'.$dw[$i]."\n";
}
$decrypt_block .= ');';
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => '',
'init_encrypt' => $init_encrypt,
'init_decrypt' => $init_decrypt,
'encrypt_block' => $encrypt_block,
'decrypt_block' => $decrypt_block
)
);
}
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
================================================
FILE: assets/libraries/phpseclib/Crypt/TripleDES.php
================================================
* setKey('abcdefghijklmnopqrstuvwx');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $des->decrypt($des->encrypt($plaintext));
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_TripleDES
* @author Jim Wigginton
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_DES
*/
if (!class_exists('Crypt_DES')) {
include_once 'DES.php';
}
/**#@+
* @access public
* @see self::Crypt_TripleDES()
*/
/**
* Encrypt / decrypt using inner chaining
*
* Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
*/
define('CRYPT_MODE_3CBC', -2);
/**
* BC version of the above.
*/
define('CRYPT_DES_MODE_3CBC', -2);
/**
* Encrypt / decrypt using outer chaining
*
* Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC.
*/
define('CRYPT_MODE_CBC3', CRYPT_MODE_CBC);
/**
* BC version of the above.
*/
define('CRYPT_DES_MODE_CBC3', CRYPT_MODE_CBC3);
/**#@-*/
/**
* Pure-PHP implementation of Triple DES.
*
* @package Crypt_TripleDES
* @author Jim Wigginton
* @access public
*/
class Crypt_TripleDES extends Crypt_DES
{
/**
* Key Length (in bytes)
*
* @see Crypt_TripleDES::setKeyLength()
* @var int
* @access private
*/
var $key_length = 24;
/**
* The default salt used by setPassword()
*
* @see Crypt_Base::password_default_salt
* @see Crypt_Base::setPassword()
* @var string
* @access private
*/
var $password_default_salt = 'phpseclib';
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_DES::const_namespace
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'DES';
/**
* The mcrypt specific name of the cipher
*
* @see Crypt_DES::cipher_name_mcrypt
* @see Crypt_Base::cipher_name_mcrypt
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'tripledes';
/**
* Optimizing value while CFB-encrypting
*
* @see Crypt_Base::cfb_init_len
* @var int
* @access private
*/
var $cfb_init_len = 750;
/**
* max possible size of $key
*
* @see self::setKey()
* @see Crypt_DES::setKey()
* @var string
* @access private
*/
var $key_length_max = 24;
/**
* Internal flag whether using CRYPT_DES_MODE_3CBC or not
*
* @var bool
* @access private
*/
var $mode_3cbc;
/**
* The Crypt_DES objects
*
* Used only if $mode_3cbc === true
*
* @var array
* @access private
*/
var $des;
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
*
* - CRYPT_DES_MODE_ECB
*
* - CRYPT_DES_MODE_CBC
*
* - CRYPT_DES_MODE_CTR
*
* - CRYPT_DES_MODE_CFB
*
* - CRYPT_DES_MODE_OFB
*
* - CRYPT_DES_MODE_3CBC
*
* If not explicitly set, CRYPT_DES_MODE_CBC will be used.
*
* @see Crypt_DES::Crypt_DES()
* @see Crypt_Base::Crypt_Base()
* @param int $mode
* @access public
*/
function __construct($mode = CRYPT_MODE_CBC)
{
switch ($mode) {
// In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC
// and additional flag us internally as 3CBC
case CRYPT_DES_MODE_3CBC:
parent::Crypt_Base(CRYPT_MODE_CBC);
$this->mode_3cbc = true;
// This three $des'es will do the 3CBC work (if $key > 64bits)
$this->des = array(
new Crypt_DES(CRYPT_MODE_CBC),
new Crypt_DES(CRYPT_MODE_CBC),
new Crypt_DES(CRYPT_MODE_CBC),
);
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
$this->des[0]->disablePadding();
$this->des[1]->disablePadding();
$this->des[2]->disablePadding();
break;
// If not 3CBC, we init as usual
default:
parent::__construct($mode);
}
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param int $mode
* @access public
*/
function Crypt_TripleDES($mode = CRYPT_MODE_CBC)
{
$this->__construct($mode);
}
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
*
* @see Crypt_Base::Crypt_Base()
* @param int $engine
* @access public
* @return bool
*/
function isValidEngine($engine)
{
if ($engine == CRYPT_ENGINE_OPENSSL) {
$this->cipher_name_openssl_ecb = 'des-ede3';
$mode = $this->_openssl_translate_mode();
$this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode;
}
return parent::isValidEngine($engine);
}
/**
* Sets the initialization vector. (optional)
*
* SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explicitly set, it'll be assumed
* to be all zero's.
*
* @see Crypt_Base::setIV()
* @access public
* @param string $iv
*/
function setIV($iv)
{
parent::setIV($iv);
if ($this->mode_3cbc) {
$this->des[0]->setIV($iv);
$this->des[1]->setIV($iv);
$this->des[2]->setIV($iv);
}
}
/**
* Sets the key length.
*
* Valid key lengths are 64, 128 and 192
*
* @see Crypt_Base:setKeyLength()
* @access public
* @param int $length
*/
function setKeyLength($length)
{
$length >>= 3;
switch (true) {
case $length <= 8:
$this->key_length = 8;
break;
case $length <= 16:
$this->key_length = 16;
break;
default:
$this->key_length = 24;
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
* 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
*
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
*
* If the key is not explicitly set, it'll be assumed to be all null bytes.
*
* @access public
* @see Crypt_DES::setKey()
* @see Crypt_Base::setKey()
* @param string $key
*/
function setKey($key)
{
$length = $this->explicit_key_length ? $this->key_length : strlen($key);
if ($length > 8) {
$key = str_pad(substr($key, 0, 24), 24, chr(0));
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
// http://php.net/function.mcrypt-encrypt#47973
$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
} else {
$key = str_pad($key, 8, chr(0));
}
parent::setKey($key);
// And in case of CRYPT_DES_MODE_3CBC:
// if key <= 64bits we not need the 3 $des to work,
// because we will then act as regular DES-CBC with just a <= 64bit key.
// So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des.
if ($this->mode_3cbc && $length > 8) {
$this->des[0]->setKey(substr($key, 0, 8));
$this->des[1]->setKey(substr($key, 8, 8));
$this->des[2]->setKey(substr($key, 16, 8));
}
}
/**
* Encrypts a message.
*
* @see Crypt_Base::encrypt()
* @access public
* @param string $plaintext
* @return string $cipertext
*/
function encrypt($plaintext)
{
// parent::en/decrypt() is able to do all the work for all modes and keylengths,
// except for: CRYPT_MODE_3CBC (inner chaining CBC) with a key > 64bits
// if the key is smaller then 8, do what we'd normally do
if ($this->mode_3cbc && strlen($this->key) > 8) {
return $this->des[2]->encrypt(
$this->des[1]->decrypt(
$this->des[0]->encrypt(
$this->_pad($plaintext)
)
)
);
}
return parent::encrypt($plaintext);
}
/**
* Decrypts a message.
*
* @see Crypt_Base::decrypt()
* @access public
* @param string $ciphertext
* @return string $plaintext
*/
function decrypt($ciphertext)
{
if ($this->mode_3cbc && strlen($this->key) > 8) {
return $this->_unpad(
$this->des[0]->decrypt(
$this->des[1]->encrypt(
$this->des[2]->decrypt(
str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
)
)
)
);
}
return parent::decrypt($ciphertext);
}
/**
* Treat consecutive "packets" as if they are a continuous buffer.
*
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
* will yield different outputs:
*
*
* echo $des->encrypt(substr($plaintext, 0, 8));
* echo $des->encrypt(substr($plaintext, 8, 8));
*
*
* echo $des->encrypt($plaintext);
*
*
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
* another, as demonstrated with the following:
*
*
* $des->encrypt(substr($plaintext, 0, 8));
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
*
*
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
*
*
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
*
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
* however, they are also less intuitive and more likely to cause you problems.
*
* @see Crypt_Base::enableContinuousBuffer()
* @see self::disableContinuousBuffer()
* @access public
*/
function enableContinuousBuffer()
{
parent::enableContinuousBuffer();
if ($this->mode_3cbc) {
$this->des[0]->enableContinuousBuffer();
$this->des[1]->enableContinuousBuffer();
$this->des[2]->enableContinuousBuffer();
}
}
/**
* Treat consecutive packets as if they are a discontinuous buffer.
*
* The default behavior.
*
* @see Crypt_Base::disableContinuousBuffer()
* @see self::enableContinuousBuffer()
* @access public
*/
function disableContinuousBuffer()
{
parent::disableContinuousBuffer();
if ($this->mode_3cbc) {
$this->des[0]->disableContinuousBuffer();
$this->des[1]->disableContinuousBuffer();
$this->des[2]->disableContinuousBuffer();
}
}
/**
* Creates the key schedule
*
* @see Crypt_DES::_setupKey()
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
switch (true) {
// if $key <= 64bits we configure our internal pure-php cipher engine
// to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same.
case strlen($this->key) <= 8:
$this->des_rounds = 1;
break;
// otherwise, if $key > 64bits, we configure our engine to work as 3DES.
default:
$this->des_rounds = 3;
// (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately.
if ($this->mode_3cbc) {
$this->des[0]->_setupKey();
$this->des[1]->_setupKey();
$this->des[2]->_setupKey();
// because $des[0-2] will, now, do all the work we can return here
// not need unnecessary stress parent::_setupKey() with our, now unused, $key.
return;
}
}
// setup our key
parent::_setupKey();
}
/**
* Sets the internal crypt engine
*
* @see Crypt_Base::Crypt_Base()
* @see Crypt_Base::setPreferredEngine()
* @param int $engine
* @access public
* @return int
*/
function setPreferredEngine($engine)
{
if ($this->mode_3cbc) {
$this->des[0]->setPreferredEngine($engine);
$this->des[1]->setPreferredEngine($engine);
$this->des[2]->setPreferredEngine($engine);
}
return parent::setPreferredEngine($engine);
}
}
================================================
FILE: assets/libraries/phpseclib/Crypt/Twofish.php
================================================
* setKey('12345678901234567890123456789012');
*
* $plaintext = str_repeat('a', 1024);
*
* echo $twofish->decrypt($twofish->encrypt($plaintext));
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Crypt
* @package Crypt_Twofish
* @author Jim Wigginton
* @author Hans-Juergen Petrich
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_Base
*
* Base cipher class
*/
if (!class_exists('Crypt_Base')) {
include_once 'Base.php';
}
/**#@+
* @access public
* @see self::encrypt()
* @see self::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_TWOFISH_MODE_CTR', CRYPT_MODE_CTR);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
*/
define('CRYPT_TWOFISH_MODE_ECB', CRYPT_MODE_ECB);
/**
* Encrypt / decrypt using the Code Book Chaining mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_TWOFISH_MODE_CBC', CRYPT_MODE_CBC);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
define('CRYPT_TWOFISH_MODE_CFB', CRYPT_MODE_CFB);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
*/
define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**
* Pure-PHP implementation of Twofish.
*
* @package Crypt_Twofish
* @author Jim Wigginton
* @author Hans-Juergen Petrich
* @access public
*/
class Crypt_Twofish extends Crypt_Base
{
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var string
* @access private
*/
var $const_namespace = 'TWOFISH';
/**
* The mcrypt specific name of the cipher
*
* @see Crypt_Base::cipher_name_mcrypt
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'twofish';
/**
* Optimizing value while CFB-encrypting
*
* @see Crypt_Base::cfb_init_len
* @var int
* @access private
*/
var $cfb_init_len = 800;
/**
* Q-Table
*
* @var array
* @access private
*/
var $q0 = array(
0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
);
/**
* Q-Table
*
* @var array
* @access private
*/
var $q1 = array(
0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
);
/**
* M-Table
*
* @var array
* @access private
*/
var $m0 = array(
0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
);
/**
* M-Table
*
* @var array
* @access private
*/
var $m1 = array(
0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
);
/**
* M-Table
*
* @var array
* @access private
*/
var $m2 = array(
0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
);
/**
* M-Table
*
* @var array
* @access private
*/
var $m3 = array(
0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
);
/**
* The Key Schedule Array
*
* @var array
* @access private
*/
var $K = array();
/**
* The Key depended S-Table 0
*
* @var array
* @access private
*/
var $S0 = array();
/**
* The Key depended S-Table 1
*
* @var array
* @access private
*/
var $S1 = array();
/**
* The Key depended S-Table 2
*
* @var array
* @access private
*/
var $S2 = array();
/**
* The Key depended S-Table 3
*
* @var array
* @access private
*/
var $S3 = array();
/**
* Holds the last used key
*
* @var array
* @access private
*/
var $kl;
/**
* The Key Length (in bytes)
*
* @see Crypt_Twofish::setKeyLength()
* @var int
* @access private
*/
var $key_length = 16;
/**
* Sets the key length.
*
* Valid key lengths are 128, 192 or 256 bits
*
* @access public
* @param int $length
*/
function setKeyLength($length)
{
switch (true) {
case $length <= 128:
$this->key_length = 16;
break;
case $length <= 192:
$this->key_length = 24;
break;
default:
$this->key_length = 32;
}
parent::setKeyLength($length);
}
/**
* Setup the key (expansion)
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
// already expanded
return;
}
$this->kl = array('key' => $this->key);
/* Key expanding and generating the key-depended s-boxes */
$le_longs = unpack('V*', $this->key);
$key = unpack('C*', $this->key);
$m0 = $this->m0;
$m1 = $this->m1;
$m2 = $this->m2;
$m3 = $this->m3;
$q0 = $this->q0;
$q1 = $this->q1;
$K = $S0 = $S1 = $S2 = $S3 = array();
switch (strlen($this->key)) {
case 16:
list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[1], $le_longs[2]);
list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[3], $le_longs[4]);
for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
$A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
$m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
$m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
$m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
$B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
$m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
$m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
$A = $this->safe_intval($A + $B);
$K[] = $A;
$A = $this->safe_intval($A + $B);
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
$S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
$S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
$S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
}
break;
case 24:
list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[1], $le_longs[2]);
list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[3], $le_longs[4]);
list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[5], $le_longs[6]);
for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
$A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
$m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
$m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
$m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
$B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
$m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
$m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
$A = $this->safe_intval($A + $B);
$K[] = $A;
$A = $this->safe_intval($A + $B);
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
$S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
$S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
$S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
}
break;
default: // 32
list($sf, $se, $sd, $sc) = $this->_mdsrem($le_longs[1], $le_longs[2]);
list($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[3], $le_longs[4]);
list($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[5], $le_longs[6]);
list($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[7], $le_longs[8]);
for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
$A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
$m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
$m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
$m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
$B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
$m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
$m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
$m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
$B = ($B << 8) | ($B >> 24 & 0xff);
$A = $this->safe_intval($A + $B);
$K[] = $A;
$A = $this->safe_intval($A + $B);
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
}
for ($i = 0; $i < 256; ++$i) {
$S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
$S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
$S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
$S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
}
}
$this->K = $K;
$this->S0 = $S0;
$this->S1 = $S1;
$this->S2 = $S2;
$this->S3 = $S3;
}
/**
* _mdsrem function using by the twofish cipher algorithm
*
* @access private
* @param string $A
* @param string $B
* @return array
*/
function _mdsrem($A, $B)
{
// No gain by unrolling this loop.
for ($i = 0; $i < 8; ++$i) {
// Get most significant coefficient.
$t = 0xff & ($B >> 24);
// Shift the others up.
$B = ($B << 8) | (0xff & ($A >> 24));
$A<<= 8;
$u = $t << 1;
// Subtract the modular polynomial on overflow.
if ($t & 0x80) {
$u^= 0x14d;
}
// Remove t * (a * x^2 + 1).
$B ^= $t ^ ($u << 16);
// Form u = a*t + t/a = t*(a + 1/a).
$u^= 0x7fffffff & ($t >> 1);
// Add the modular polynomial on underflow.
if ($t & 0x01) {
$u^= 0xa6 ;
}
// Remove t * (a + 1/a) * (x^3 + x).
$B^= ($u << 24) | ($u << 8);
}
return array(
0xff & $B >> 24,
0xff & $B >> 16,
0xff & $B >> 8,
0xff & $B);
}
/**
* Encrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _encryptBlock($in)
{
$S0 = $this->S0;
$S1 = $this->S1;
$S2 = $this->S2;
$S3 = $this->S3;
$K = $this->K;
$in = unpack("V4", $in);
$R0 = $K[0] ^ $in[1];
$R1 = $K[1] ^ $in[2];
$R2 = $K[2] ^ $in[3];
$R3 = $K[3] ^ $in[4];
$ki = 7;
while ($ki < 39) {
$t0 = $S0[ $R0 & 0xff] ^
$S1[($R0 >> 8) & 0xff] ^
$S2[($R0 >> 16) & 0xff] ^
$S3[($R0 >> 24) & 0xff];
$t1 = $S0[($R1 >> 24) & 0xff] ^
$S1[ $R1 & 0xff] ^
$S2[($R1 >> 8) & 0xff] ^
$S3[($R1 >> 16) & 0xff];
$R2^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
$R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
$R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
$t0 = $S0[ $R2 & 0xff] ^
$S1[($R2 >> 8) & 0xff] ^
$S2[($R2 >> 16) & 0xff] ^
$S3[($R2 >> 24) & 0xff];
$t1 = $S0[($R3 >> 24) & 0xff] ^
$S1[ $R3 & 0xff] ^
$S2[($R3 >> 8) & 0xff] ^
$S3[($R3 >> 16) & 0xff];
$R0^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
$R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
}
// @codingStandardsIgnoreStart
return pack("V4", $K[4] ^ $R2,
$K[5] ^ $R3,
$K[6] ^ $R0,
$K[7] ^ $R1);
// @codingStandardsIgnoreEnd
}
/**
* Decrypts a block
*
* @access private
* @param string $in
* @return string
*/
function _decryptBlock($in)
{
$S0 = $this->S0;
$S1 = $this->S1;
$S2 = $this->S2;
$S3 = $this->S3;
$K = $this->K;
$in = unpack("V4", $in);
$R0 = $K[4] ^ $in[1];
$R1 = $K[5] ^ $in[2];
$R2 = $K[6] ^ $in[3];
$R3 = $K[7] ^ $in[4];
$ki = 40;
while ($ki > 8) {
$t0 = $S0[$R0 & 0xff] ^
$S1[$R0 >> 8 & 0xff] ^
$S2[$R0 >> 16 & 0xff] ^
$S3[$R0 >> 24 & 0xff];
$t1 = $S0[$R1 >> 24 & 0xff] ^
$S1[$R1 & 0xff] ^
$S2[$R1 >> 8 & 0xff] ^
$S3[$R1 >> 16 & 0xff];
$R3^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
$R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
$R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
$t0 = $S0[$R2 & 0xff] ^
$S1[$R2 >> 8 & 0xff] ^
$S2[$R2 >> 16 & 0xff] ^
$S3[$R2 >> 24 & 0xff];
$t1 = $S0[$R3 >> 24 & 0xff] ^
$S1[$R3 & 0xff] ^
$S2[$R3 >> 8 & 0xff] ^
$S3[$R3 >> 16 & 0xff];
$R1^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
$R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
}
// @codingStandardsIgnoreStart
return pack("V4", $K[0] ^ $R2,
$K[1] ^ $R3,
$K[2] ^ $R0,
$K[3] ^ $R1);
// @codingStandardsIgnoreEnd
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* @see Crypt_Base::_setupInlineCrypt()
* @access private
*/
function _setupInlineCrypt()
{
$lambda_functions =& Crypt_Twofish::_getLambdaFunctions();
// Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one.
// (Currently, for Crypt_Twofish, one generated $lambda_function cost on php5.5@32bit ~140kb unfreeable mem and ~240kb on php5.5@64bit)
$gen_hi_opt_code = (bool)(count($lambda_functions) < 10);
// Generation of a unique hash for our generated code
$code_hash = "Crypt_Twofish, {$this->mode}";
if ($gen_hi_opt_code) {
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
}
$safeint = $this->safe_intval_inline();
if (!isset($lambda_functions[$code_hash])) {
switch (true) {
case $gen_hi_opt_code:
$K = $this->K;
$init_crypt = '
static $S0, $S1, $S2, $S3;
if (!$S0) {
for ($i = 0; $i < 256; ++$i) {
$S0[] = (int)$self->S0[$i];
$S1[] = (int)$self->S1[$i];
$S2[] = (int)$self->S2[$i];
$S3[] = (int)$self->S3[$i];
}
}
';
break;
default:
$K = array();
for ($i = 0; $i < 40; ++$i) {
$K[] = '$K_' . $i;
}
$init_crypt = '
$S0 = $self->S0;
$S1 = $self->S1;
$S2 = $self->S2;
$S3 = $self->S3;
list(' . implode(',', $K) . ') = $self->K;
';
}
// Generating encrypt code:
$encrypt_block = '
$in = unpack("V4", $in);
$R0 = '.$K[0].' ^ $in[1];
$R1 = '.$K[1].' ^ $in[2];
$R2 = '.$K[2].' ^ $in[3];
$R3 = '.$K[3].' ^ $in[4];
';
for ($ki = 7, $i = 0; $i < 8; ++$i) {
$encrypt_block.= '
$t0 = $S0[ $R0 & 0xff] ^
$S1[($R0 >> 8) & 0xff] ^
$S2[($R0 >> 16) & 0xff] ^
$S3[($R0 >> 24) & 0xff];
$t1 = $S0[($R1 >> 24) & 0xff] ^
$S1[ $R1 & 0xff] ^
$S2[($R1 >> 8) & 0xff] ^
$S3[($R1 >> 16) & 0xff];
$R2^= ' . sprintf($safeint, '$t0 + $t1 + ' . $K[++$ki]) . ';
$R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
$R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
$t0 = $S0[ $R2 & 0xff] ^
$S1[($R2 >> 8) & 0xff] ^
$S2[($R2 >> 16) & 0xff] ^
$S3[($R2 >> 24) & 0xff];
$t1 = $S0[($R3 >> 24) & 0xff] ^
$S1[ $R3 & 0xff] ^
$S2[($R3 >> 8) & 0xff] ^
$S3[($R3 >> 16) & 0xff];
$R0^= ' . sprintf($safeint, '($t0 + $t1 + ' . $K[++$ki] . ')') . ';
$R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
';
}
$encrypt_block.= '
$in = pack("V4", ' . $K[4] . ' ^ $R2,
' . $K[5] . ' ^ $R3,
' . $K[6] . ' ^ $R0,
' . $K[7] . ' ^ $R1);
';
// Generating decrypt code:
$decrypt_block = '
$in = unpack("V4", $in);
$R0 = '.$K[4].' ^ $in[1];
$R1 = '.$K[5].' ^ $in[2];
$R2 = '.$K[6].' ^ $in[3];
$R3 = '.$K[7].' ^ $in[4];
';
for ($ki = 40, $i = 0; $i < 8; ++$i) {
$decrypt_block.= '
$t0 = $S0[$R0 & 0xff] ^
$S1[$R0 >> 8 & 0xff] ^
$S2[$R0 >> 16 & 0xff] ^
$S3[$R0 >> 24 & 0xff];
$t1 = $S0[$R1 >> 24 & 0xff] ^
$S1[$R1 & 0xff] ^
$S2[$R1 >> 8 & 0xff] ^
$S3[$R1 >> 16 & 0xff];
$R3^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
$R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
$R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
$t0 = $S0[$R2 & 0xff] ^
$S1[$R2 >> 8 & 0xff] ^
$S2[$R2 >> 16 & 0xff] ^
$S3[$R2 >> 24 & 0xff];
$t1 = $S0[$R3 >> 24 & 0xff] ^
$S1[$R3 & 0xff] ^
$S2[$R3 >> 8 & 0xff] ^
$S3[$R3 >> 16 & 0xff];
$R1^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
$R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
';
}
$decrypt_block.= '
$in = pack("V4", ' . $K[0] . ' ^ $R2,
' . $K[1] . ' ^ $R3,
' . $K[2] . ' ^ $R0,
' . $K[3] . ' ^ $R1);
';
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
array(
'init_crypt' => $init_crypt,
'init_encrypt' => '',
'init_decrypt' => '',
'encrypt_block' => $encrypt_block,
'decrypt_block' => $decrypt_block
)
);
}
$this->inline_crypt = $lambda_functions[$code_hash];
}
}
================================================
FILE: assets/libraries/phpseclib/File/ANSI.php
================================================
* @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Pure-PHP ANSI Decoder
*
* @package File_ANSI
* @author Jim Wigginton
* @access public
*/
class File_ANSI
{
/**
* Max Width
*
* @var int
* @access private
*/
var $max_x;
/**
* Max Height
*
* @var int
* @access private
*/
var $max_y;
/**
* Max History
*
* @var int
* @access private
*/
var $max_history;
/**
* History
*
* @var array
* @access private
*/
var $history;
/**
* History Attributes
*
* @var array
* @access private
*/
var $history_attrs;
/**
* Current Column
*
* @var int
* @access private
*/
var $x;
/**
* Current Row
*
* @var int
* @access private
*/
var $y;
/**
* Old Column
*
* @var int
* @access private
*/
var $old_x;
/**
* Old Row
*
* @var int
* @access private
*/
var $old_y;
/**
* An empty attribute cell
*
* @var object
* @access private
*/
var $base_attr_cell;
/**
* The current attribute cell
*
* @var object
* @access private
*/
var $attr_cell;
/**
* An empty attribute row
*
* @var array
* @access private
*/
var $attr_row;
/**
* The current screen text
*
* @var array
* @access private
*/
var $screen;
/**
* The current screen attributes
*
* @var array
* @access private
*/
var $attrs;
/**
* Current ANSI code
*
* @var string
* @access private
*/
var $ansi;
/**
* Tokenization
*
* @var array
* @access private
*/
var $tokenization;
/**
* Default Constructor.
*
* @return File_ANSI
* @access public
*/
function __construct()
{
$attr_cell = new stdClass();
$attr_cell->bold = false;
$attr_cell->underline = false;
$attr_cell->blink = false;
$attr_cell->background = 'black';
$attr_cell->foreground = 'white';
$attr_cell->reverse = false;
$this->base_attr_cell = clone($attr_cell);
$this->attr_cell = clone($attr_cell);
$this->setHistory(200);
$this->setDimensions(80, 24);
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @access public
*/
function File_ANSI()
{
$this->__construct($mode);
}
/**
* Set terminal width and height
*
* Resets the screen as well
*
* @param int $x
* @param int $y
* @access public
*/
function setDimensions($x, $y)
{
$this->max_x = $x - 1;
$this->max_y = $y - 1;
$this->x = $this->y = 0;
$this->history = $this->history_attrs = array();
$this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell);
$this->screen = array_fill(0, $this->max_y + 1, '');
$this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
$this->ansi = '';
}
/**
* Set the number of lines that should be logged past the terminal height
*
* @param int $x
* @param int $y
* @access public
*/
function setHistory($history)
{
$this->max_history = $history;
}
/**
* Load a string
*
* @param string $source
* @access public
*/
function loadString($source)
{
$this->setDimensions($this->max_x + 1, $this->max_y + 1);
$this->appendString($source);
}
/**
* Appdend a string
*
* @param string $source
* @access public
*/
function appendString($source)
{
$this->tokenization = array('');
for ($i = 0; $i < strlen($source); $i++) {
if (strlen($this->ansi)) {
$this->ansi.= $source[$i];
$chr = ord($source[$i]);
// http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements
// single character CSI's not currently supported
switch (true) {
case $this->ansi == "\x1B=":
$this->ansi = '';
continue 2;
case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
break;
default:
continue 2;
}
$this->tokenization[] = $this->ansi;
$this->tokenization[] = '';
// http://ascii-table.com/ansi-escape-sequences-vt-100.php
switch ($this->ansi) {
case "\x1B[H": // Move cursor to upper left corner
$this->old_x = $this->x;
$this->old_y = $this->y;
$this->x = $this->y = 0;
break;
case "\x1B[J": // Clear screen from cursor down
$this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
$this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));
$this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
$this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));
if (count($this->history) == $this->max_history) {
array_shift($this->history);
array_shift($this->history_attrs);
}
case "\x1B[K": // Clear screen from cursor right
$this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - $this->x - 1, $this->base_attr_cell));
break;
case "\x1B[2K": // Clear entire line
$this->screen[$this->y] = str_repeat(' ', $this->x);
$this->attrs[$this->y] = $this->attr_row;
break;
case "\x1B[?1h": // set cursor key to application
case "\x1B[?25h": // show the cursor
case "\x1B(B": // set united states g0 character set
break;
case "\x1BE": // Move to next line
$this->_newLine();
$this->x = 0;
break;
default:
switch (true) {
case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): // Move cursor down n lines
$this->old_y = $this->y;
$this->y+= $match[1];
break;
case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
$this->old_x = $this->x;
$this->old_y = $this->y;
$this->x = $match[2] - 1;
$this->y = $match[1] - 1;
break;
case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
$this->old_x = $this->x;
$this->x+= $match[1];
break;
case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
$this->old_x = $this->x;
$this->x-= $match[1];
if ($this->x < 0) {
$this->x = 0;
}
break;
case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
break;
case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
$attr_cell = &$this->attr_cell;
$mods = explode(';', $match[1]);
foreach ($mods as $mod) {
switch ($mod) {
case 0: // Turn off character attributes
$attr_cell = clone($this->base_attr_cell);
break;
case 1: // Turn bold mode on
$attr_cell->bold = true;
break;
case 4: // Turn underline mode on
$attr_cell->underline = true;
break;
case 5: // Turn blinking mode on
$attr_cell->blink = true;
break;
case 7: // Turn reverse video on
$attr_cell->reverse = !$attr_cell->reverse;
$temp = $attr_cell->background;
$attr_cell->background = $attr_cell->foreground;
$attr_cell->foreground = $temp;
break;
default: // set colors
//$front = $attr_cell->reverse ? &$attr_cell->background : &$attr_cell->foreground;
$front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' };
//$back = $attr_cell->reverse ? &$attr_cell->foreground : &$attr_cell->background;
$back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' };
switch ($mod) {
// @codingStandardsIgnoreStart
case 30: $front = 'black'; break;
case 31: $front = 'red'; break;
case 32: $front = 'green'; break;
case 33: $front = 'yellow'; break;
case 34: $front = 'blue'; break;
case 35: $front = 'magenta'; break;
case 36: $front = 'cyan'; break;
case 37: $front = 'white'; break;
case 40: $back = 'black'; break;
case 41: $back = 'red'; break;
case 42: $back = 'green'; break;
case 43: $back = 'yellow'; break;
case 44: $back = 'blue'; break;
case 45: $back = 'magenta'; break;
case 46: $back = 'cyan'; break;
case 47: $back = 'white'; break;
// @codingStandardsIgnoreEnd
default:
//user_error('Unsupported attribute: ' . $mod);
$this->ansi = '';
break 2;
}
}
}
break;
default:
//user_error("{$this->ansi} is unsupported\r\n");
}
}
$this->ansi = '';
continue;
}
$this->tokenization[count($this->tokenization) - 1].= $source[$i];
switch ($source[$i]) {
case "\r":
$this->x = 0;
break;
case "\n":
$this->_newLine();
break;
case "\x08": // backspace
if ($this->x) {
$this->x--;
$this->attrs[$this->y][$this->x] = clone($this->base_attr_cell);
$this->screen[$this->y] = substr_replace(
$this->screen[$this->y],
$source[$i],
$this->x,
1
);
}
break;
case "\x0F": // shift
break;
case "\x1B": // start ANSI escape code
$this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1);
//if (!strlen($this->tokenization[count($this->tokenization) - 1])) {
// array_pop($this->tokenization);
//}
$this->ansi.= "\x1B";
break;
default:
$this->attrs[$this->y][$this->x] = clone($this->attr_cell);
if ($this->x > strlen($this->screen[$this->y])) {
$this->screen[$this->y] = str_repeat(' ', $this->x);
}
$this->screen[$this->y] = substr_replace(
$this->screen[$this->y],
$source[$i],
$this->x,
1
);
if ($this->x > $this->max_x) {
$this->x = 0;
$this->_newLine();
} else {
$this->x++;
}
}
}
}
/**
* Add a new line
*
* Also update the $this->screen and $this->history buffers
*
* @access private
*/
function _newLine()
{
//if ($this->y < $this->max_y) {
// $this->y++;
//}
while ($this->y >= $this->max_y) {
$this->history = array_merge($this->history, array(array_shift($this->screen)));
$this->screen[] = '';
$this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs)));
$this->attrs[] = $this->attr_row;
if (count($this->history) >= $this->max_history) {
array_shift($this->history);
array_shift($this->history_attrs);
}
$this->y--;
}
$this->y++;
}
/**
* Returns the current coordinate without preformating
*
* @access private
* @return string
*/
function _processCoordinate($last_attr, $cur_attr, $char)
{
$output = '';
if ($last_attr != $cur_attr) {
$close = $open = '';
if ($last_attr->foreground != $cur_attr->foreground) {
if ($cur_attr->foreground != 'white') {
$open.= '';
}
if ($last_attr->foreground != 'white') {
$close = ' ' . $close;
}
}
if ($last_attr->background != $cur_attr->background) {
if ($cur_attr->background != 'black') {
$open.= '';
}
if ($last_attr->background != 'black') {
$close = ' ' . $close;
}
}
if ($last_attr->bold != $cur_attr->bold) {
if ($cur_attr->bold) {
$open.= '';
} else {
$close = ' ' . $close;
}
}
if ($last_attr->underline != $cur_attr->underline) {
if ($cur_attr->underline) {
$open.= '';
} else {
$close = ' ' . $close;
}
}
if ($last_attr->blink != $cur_attr->blink) {
if ($cur_attr->blink) {
$open.= '';
} else {
$close = ' ' . $close;
}
}
$output.= $close . $open;
}
$output.= htmlspecialchars($char);
return $output;
}
/**
* Returns the current screen without preformating
*
* @access private
* @return string
*/
function _getScreen()
{
$output = '';
$last_attr = $this->base_attr_cell;
for ($i = 0; $i <= $this->max_y; $i++) {
for ($j = 0; $j <= $this->max_x; $j++) {
$cur_attr = $this->attrs[$i][$j];
$output.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->screen[$i][$j]) ? $this->screen[$i][$j] : '');
$last_attr = $this->attrs[$i][$j];
}
$output.= "\r\n";
}
$output = substr($output, 0, -2);
// close any remaining open tags
$output.= $this->_processCoordinate($last_attr, $this->base_attr_cell, '');
return rtrim($output);
}
/**
* Returns the current screen
*
* @access public
* @return string
*/
function getScreen()
{
return '' . $this->_getScreen() . ' ';
}
/**
* Returns the current screen and the x previous lines
*
* @access public
* @return string
*/
function getHistory()
{
$scrollback = '';
$last_attr = $this->base_attr_cell;
for ($i = 0; $i < count($this->history); $i++) {
for ($j = 0; $j <= $this->max_x + 1; $j++) {
$cur_attr = $this->history_attrs[$i][$j];
$scrollback.= $this->_processCoordinate($last_attr, $cur_attr, isset($this->history[$i][$j]) ? $this->history[$i][$j] : '');
$last_attr = $this->history_attrs[$i][$j];
}
$scrollback.= "\r\n";
}
$base_attr_cell = $this->base_attr_cell;
$this->base_attr_cell = $last_attr;
$scrollback.= $this->_getScreen();
$this->base_attr_cell = $base_attr_cell;
return '' . $scrollback . ' ';
}
}
================================================
FILE: assets/libraries/phpseclib/File/ASN1.php
================================================
* @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**#@+
* Tag Classes
*
* @access private
* @link http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
*/
define('FILE_ASN1_CLASS_UNIVERSAL', 0);
define('FILE_ASN1_CLASS_APPLICATION', 1);
define('FILE_ASN1_CLASS_CONTEXT_SPECIFIC', 2);
define('FILE_ASN1_CLASS_PRIVATE', 3);
/**#@-*/
/**#@+
* Tag Classes
*
* @access private
* @link http://www.obj-sys.com/asn1tutorial/node124.html
*/
define('FILE_ASN1_TYPE_BOOLEAN', 1);
define('FILE_ASN1_TYPE_INTEGER', 2);
define('FILE_ASN1_TYPE_BIT_STRING', 3);
define('FILE_ASN1_TYPE_OCTET_STRING', 4);
define('FILE_ASN1_TYPE_NULL', 5);
define('FILE_ASN1_TYPE_OBJECT_IDENTIFIER', 6);
//define('FILE_ASN1_TYPE_OBJECT_DESCRIPTOR', 7);
//define('FILE_ASN1_TYPE_INSTANCE_OF', 8); // EXTERNAL
define('FILE_ASN1_TYPE_REAL', 9);
define('FILE_ASN1_TYPE_ENUMERATED', 10);
//define('FILE_ASN1_TYPE_EMBEDDED', 11);
define('FILE_ASN1_TYPE_UTF8_STRING', 12);
//define('FILE_ASN1_TYPE_RELATIVE_OID', 13);
define('FILE_ASN1_TYPE_SEQUENCE', 16); // SEQUENCE OF
define('FILE_ASN1_TYPE_SET', 17); // SET OF
/**#@-*/
/**#@+
* More Tag Classes
*
* @access private
* @link http://www.obj-sys.com/asn1tutorial/node10.html
*/
define('FILE_ASN1_TYPE_NUMERIC_STRING', 18);
define('FILE_ASN1_TYPE_PRINTABLE_STRING', 19);
define('FILE_ASN1_TYPE_TELETEX_STRING', 20); // T61String
define('FILE_ASN1_TYPE_VIDEOTEX_STRING', 21);
define('FILE_ASN1_TYPE_IA5_STRING', 22);
define('FILE_ASN1_TYPE_UTC_TIME', 23);
define('FILE_ASN1_TYPE_GENERALIZED_TIME', 24);
define('FILE_ASN1_TYPE_GRAPHIC_STRING', 25);
define('FILE_ASN1_TYPE_VISIBLE_STRING', 26); // ISO646String
define('FILE_ASN1_TYPE_GENERAL_STRING', 27);
define('FILE_ASN1_TYPE_UNIVERSAL_STRING', 28);
//define('FILE_ASN1_TYPE_CHARACTER_STRING', 29);
define('FILE_ASN1_TYPE_BMP_STRING', 30);
/**#@-*/
/**#@+
* Tag Aliases
*
* These tags are kinda place holders for other tags.
*
* @access private
*/
define('FILE_ASN1_TYPE_CHOICE', -1);
define('FILE_ASN1_TYPE_ANY', -2);
/**#@-*/
/**
* ASN.1 Element
*
* Bypass normal encoding rules in File_ASN1::encodeDER()
*
* @package File_ASN1
* @author Jim Wigginton
* @access public
*/
class File_ASN1_Element
{
/**
* Raw element value
*
* @var string
* @access private
*/
var $element;
/**
* Constructor
*
* @param string $encoded
* @return File_ASN1_Element
* @access public
*/
function __construct($encoded)
{
$this->element = $encoded;
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param int $mode
* @access public
*/
function File_ASN1_Element($encoded)
{
$this->__construct($encoded);
}
}
/**
* Pure-PHP ASN.1 Parser
*
* @package File_ASN1
* @author Jim Wigginton
* @access public
*/
class File_ASN1
{
/**
* ASN.1 object identifier
*
* @var array
* @access private
* @link http://en.wikipedia.org/wiki/Object_identifier
*/
var $oids = array();
/**
* Default date format
*
* @var string
* @access private
* @link http://php.net/class.datetime
*/
var $format = 'D, d M Y H:i:s O';
/**
* Default date format
*
* @var array
* @access private
* @see self::setTimeFormat()
* @see self::asn1map()
* @link http://php.net/class.datetime
*/
var $encoded;
/**
* Filters
*
* If the mapping type is FILE_ASN1_TYPE_ANY what do we actually encode it as?
*
* @var array
* @access private
* @see self::_encode_der()
*/
var $filters;
/**
* Type mapping table for the ANY type.
*
* Structured or unknown types are mapped to a FILE_ASN1_Element.
* Unambiguous types get the direct mapping (int/real/bool).
* Others are mapped as a choice, with an extra indexing level.
*
* @var array
* @access public
*/
var $ANYmap = array(
FILE_ASN1_TYPE_BOOLEAN => true,
FILE_ASN1_TYPE_INTEGER => true,
FILE_ASN1_TYPE_BIT_STRING => 'bitString',
FILE_ASN1_TYPE_OCTET_STRING => 'octetString',
FILE_ASN1_TYPE_NULL => 'null',
FILE_ASN1_TYPE_OBJECT_IDENTIFIER => 'objectIdentifier',
FILE_ASN1_TYPE_REAL => true,
FILE_ASN1_TYPE_ENUMERATED => 'enumerated',
FILE_ASN1_TYPE_UTF8_STRING => 'utf8String',
FILE_ASN1_TYPE_NUMERIC_STRING => 'numericString',
FILE_ASN1_TYPE_PRINTABLE_STRING => 'printableString',
FILE_ASN1_TYPE_TELETEX_STRING => 'teletexString',
FILE_ASN1_TYPE_VIDEOTEX_STRING => 'videotexString',
FILE_ASN1_TYPE_IA5_STRING => 'ia5String',
FILE_ASN1_TYPE_UTC_TIME => 'utcTime',
FILE_ASN1_TYPE_GENERALIZED_TIME => 'generalTime',
FILE_ASN1_TYPE_GRAPHIC_STRING => 'graphicString',
FILE_ASN1_TYPE_VISIBLE_STRING => 'visibleString',
FILE_ASN1_TYPE_GENERAL_STRING => 'generalString',
FILE_ASN1_TYPE_UNIVERSAL_STRING => 'universalString',
//FILE_ASN1_TYPE_CHARACTER_STRING => 'characterString',
FILE_ASN1_TYPE_BMP_STRING => 'bmpString'
);
/**
* String type to character size mapping table.
*
* Non-convertable types are absent from this table.
* size == 0 indicates variable length encoding.
*
* @var array
* @access public
*/
var $stringTypeSize = array(
FILE_ASN1_TYPE_UTF8_STRING => 0,
FILE_ASN1_TYPE_BMP_STRING => 2,
FILE_ASN1_TYPE_UNIVERSAL_STRING => 4,
FILE_ASN1_TYPE_PRINTABLE_STRING => 1,
FILE_ASN1_TYPE_TELETEX_STRING => 1,
FILE_ASN1_TYPE_IA5_STRING => 1,
FILE_ASN1_TYPE_VISIBLE_STRING => 1,
);
/**
* Default Constructor.
*
* @access public
*/
function __construct()
{
static $static_init = null;
if (!$static_init) {
$static_init = true;
if (!class_exists('Math_BigInteger')) {
include_once 'Math/BigInteger.php';
}
}
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @access public
*/
function File_ASN1()
{
$this->__construct($mode);
}
/**
* Parse BER-encoding
*
* Serves a similar purpose to openssl's asn1parse
*
* @param string $encoded
* @return array
* @access public
*/
function decodeBER($encoded)
{
if (is_object($encoded) && strtolower(get_class($encoded)) == 'file_asn1_element') {
$encoded = $encoded->element;
}
$this->encoded = $encoded;
// encapsulate in an array for BC with the old decodeBER
return array($this->_decode_ber($encoded));
}
/**
* Parse BER-encoding (Helper function)
*
* Sometimes we want to get the BER encoding of a particular tag. $start lets us do that without having to reencode.
* $encoded is passed by reference for the recursive calls done for FILE_ASN1_TYPE_BIT_STRING and
* FILE_ASN1_TYPE_OCTET_STRING. In those cases, the indefinite length is used.
*
* @param string $encoded
* @param int $start
* @param int $encoded_pos
* @return array
* @access private
*/
function _decode_ber($encoded, $start = 0, $encoded_pos = 0)
{
$current = array('start' => $start);
$type = ord($encoded[$encoded_pos++]);
$start++;
$constructed = ($type >> 5) & 1;
$tag = $type & 0x1F;
if ($tag == 0x1F) {
$tag = 0;
// process septets (since the eighth bit is ignored, it's not an octet)
do {
$loop = ord($encoded[0]) >> 7;
$tag <<= 7;
$tag |= ord($encoded[$encoded_pos++]) & 0x7F;
$start++;
} while ($loop);
}
// Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
$length = ord($encoded[$encoded_pos++]);
$start++;
if ($length == 0x80) { // indefinite length
// "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
// immediately available." -- paragraph 8.1.3.2.c
$length = strlen($encoded) - $encoded_pos;
} elseif ($length & 0x80) { // definite length, long form
// technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
// support it up to four.
$length&= 0x7F;
$temp = substr($encoded, $encoded_pos, $length);
$encoded_pos += $length;
// tags of indefinte length don't really have a header length; this length includes the tag
$current+= array('headerlength' => $length + 2);
$start+= $length;
extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
} else {
$current+= array('headerlength' => 2);
}
if ($length > (strlen($encoded) - $encoded_pos)) {
return false;
}
$content = substr($encoded, $encoded_pos, $length);
$content_pos = 0;
// at this point $length can be overwritten. it's only accurate for definite length things as is
/* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
built-in types. It defines an application-independent data type that must be distinguishable from all other
data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
data type; the term CONTEXT-SPECIFIC does not appear.
-- http://www.obj-sys.com/asn1tutorial/node12.html */
$class = ($type >> 6) & 3;
switch ($class) {
case FILE_ASN1_CLASS_APPLICATION:
case FILE_ASN1_CLASS_PRIVATE:
case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
if (!$constructed) {
return array(
'type' => $class,
'constant' => $tag,
'content' => $content,
'length' => $length + $start - $current['start']
);
}
$newcontent = array();
$remainingLength = $length;
while ($remainingLength > 0) {
$temp = $this->_decode_ber($content, $start, $content_pos);
if ($temp === false) {
break;
}
$length = $temp['length'];
// end-of-content octets - see paragraph 8.1.5
if (substr($content, $content_pos + $length, 2) == "\0\0") {
$length+= 2;
$start+= $length;
$newcontent[] = $temp;
break;
}
$start+= $length;
$remainingLength-= $length;
$newcontent[] = $temp;
$content_pos += $length;
}
return array(
'type' => $class,
'constant' => $tag,
// the array encapsulation is for BC with the old format
'content' => $newcontent,
// the only time when $content['headerlength'] isn't defined is when the length is indefinite.
// the absence of $content['headerlength'] is how we know if something is indefinite or not.
// technically, it could be defined to be 2 and then another indicator could be used but whatever.
'length' => $start - $current['start']
) + $current;
}
$current+= array('type' => $tag);
// decode UNIVERSAL tags
switch ($tag) {
case FILE_ASN1_TYPE_BOOLEAN:
// "The contents octets shall consist of a single octet." -- paragraph 8.2.1
//if (strlen($content) != 1) {
// return false;
//}
$current['content'] = (bool) ord($content[$content_pos]);
break;
case FILE_ASN1_TYPE_INTEGER:
case FILE_ASN1_TYPE_ENUMERATED:
$current['content'] = new Math_BigInteger(substr($content, $content_pos), -256);
break;
case FILE_ASN1_TYPE_REAL: // not currently supported
return false;
case FILE_ASN1_TYPE_BIT_STRING:
// The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
// the number of unused bits in the final subsequent octet. The number shall be in the range zero to
// seven.
if (!$constructed) {
$current['content'] = substr($content, $content_pos);
} else {
$temp = $this->_decode_ber($content, $start, $content_pos);
if ($temp === false) {
return false;
}
$length-= (strlen($content) - $content_pos);
$last = count($temp) - 1;
for ($i = 0; $i < $last; $i++) {
// all subtags should be bit strings
//if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
// return false;
//}
$current['content'].= substr($temp[$i]['content'], 1);
}
// all subtags should be bit strings
//if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) {
// return false;
//}
$current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
}
break;
case FILE_ASN1_TYPE_OCTET_STRING:
if (!$constructed) {
$current['content'] = substr($content, $content_pos);
} else {
$current['content'] = '';
$length = 0;
while (substr($content, $content_pos, 2) != "\0\0") {
$temp = $this->_decode_ber($content, $length + $start, $content_pos);
if ($temp === false) {
return false;
}
$content_pos += $temp['length'];
// all subtags should be octet strings
//if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
// return false;
//}
$current['content'].= $temp['content'];
$length+= $temp['length'];
}
if (substr($content, $content_pos, 2) == "\0\0") {
$length+= 2; // +2 for the EOC
}
}
break;
case FILE_ASN1_TYPE_NULL:
// "The contents octets shall not contain any octets." -- paragraph 8.8.2
//if (strlen($content)) {
// return false;
//}
break;
case FILE_ASN1_TYPE_SEQUENCE:
case FILE_ASN1_TYPE_SET:
$offset = 0;
$current['content'] = array();
$content_len = strlen($content);
while ($content_pos < $content_len) {
// if indefinite length construction was used and we have an end-of-content string next
// see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
if (!isset($current['headerlength']) && substr($content, $content_pos, 2) == "\0\0") {
$length = $offset + 2; // +2 for the EOC
break 2;
}
$temp = $this->_decode_ber($content, $start + $offset, $content_pos);
if ($temp === false) {
return false;
}
$content_pos += $temp['length'];
$current['content'][] = $temp;
$offset+= $temp['length'];
}
break;
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
$temp = ord($content[$content_pos++]);
$current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
$valuen = 0;
// process septets
$content_len = strlen($content);
while ($content_pos < $content_len) {
$temp = ord($content[$content_pos++]);
$valuen <<= 7;
$valuen |= $temp & 0x7F;
if (~$temp & 0x80) {
$current['content'].= ".$valuen";
$valuen = 0;
}
}
// the eighth bit of the last byte should not be 1
//if ($temp >> 7) {
// return false;
//}
break;
/* Each character string type shall be encoded as if it had been declared:
[UNIVERSAL x] IMPLICIT OCTET STRING
-- X.690-0207.pdf#page=23 (paragraph 8.21.3)
Per that, we're not going to do any validation. If there are any illegal characters in the string,
we don't really care */
case FILE_ASN1_TYPE_NUMERIC_STRING:
// 0,1,2,3,4,5,6,7,8,9, and space
case FILE_ASN1_TYPE_PRINTABLE_STRING:
// Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
// hyphen, full stop, solidus, colon, equal sign, question mark
case FILE_ASN1_TYPE_TELETEX_STRING:
// The Teletex character set in CCITT's T61, space, and delete
// see http://en.wikipedia.org/wiki/Teletex#Character_sets
case FILE_ASN1_TYPE_VIDEOTEX_STRING:
// The Videotex character set in CCITT's T.100 and T.101, space, and delete
case FILE_ASN1_TYPE_VISIBLE_STRING:
// Printing character sets of international ASCII, and space
case FILE_ASN1_TYPE_IA5_STRING:
// International Alphabet 5 (International ASCII)
case FILE_ASN1_TYPE_GRAPHIC_STRING:
// All registered G sets, and space
case FILE_ASN1_TYPE_GENERAL_STRING:
// All registered C and G sets, space and delete
case FILE_ASN1_TYPE_UTF8_STRING:
// ????
case FILE_ASN1_TYPE_BMP_STRING:
$current['content'] = substr($content, $content_pos);
break;
case FILE_ASN1_TYPE_UTC_TIME:
case FILE_ASN1_TYPE_GENERALIZED_TIME:
$current['content'] = class_exists('DateTime') ?
$this->_decodeDateTime(substr($content, $content_pos), $tag) :
$this->_decodeUnixTime(substr($content, $content_pos), $tag);
default:
}
$start+= $length;
// ie. length is the length of the full TLV encoding - it's not just the length of the value
return $current + array('length' => $start - $current['start']);
}
/**
* ASN.1 Map
*
* Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
*
* "Special" mappings may be applied on a per tag-name basis via $special.
*
* @param array $decoded
* @param array $mapping
* @param array $special
* @return array
* @access public
*/
function asn1map($decoded, $mapping, $special = array())
{
if (isset($mapping['explicit']) && is_array($decoded['content'])) {
$decoded = $decoded['content'][0];
}
switch (true) {
case $mapping['type'] == FILE_ASN1_TYPE_ANY:
$intype = $decoded['type'];
if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || (ord($this->encoded[$decoded['start']]) & 0x20)) {
return new File_ASN1_Element(substr($this->encoded, $decoded['start'], $decoded['length']));
}
$inmap = $this->ANYmap[$intype];
if (is_string($inmap)) {
return array($inmap => $this->asn1map($decoded, array('type' => $intype) + $mapping, $special));
}
break;
case $mapping['type'] == FILE_ASN1_TYPE_CHOICE:
foreach ($mapping['children'] as $key => $option) {
switch (true) {
case isset($option['constant']) && $option['constant'] == $decoded['constant']:
case !isset($option['constant']) && $option['type'] == $decoded['type']:
$value = $this->asn1map($decoded, $option, $special);
break;
case !isset($option['constant']) && $option['type'] == FILE_ASN1_TYPE_CHOICE:
$v = $this->asn1map($decoded, $option, $special);
if (isset($v)) {
$value = $v;
}
}
if (isset($value)) {
if (isset($special[$key])) {
$value = call_user_func($special[$key], $value);
}
return array($key => $value);
}
}
return null;
case isset($mapping['implicit']):
case isset($mapping['explicit']):
case $decoded['type'] == $mapping['type']:
break;
default:
// if $decoded['type'] and $mapping['type'] are both strings, but different types of strings,
// let it through
switch (true) {
case $decoded['type'] < 18: // FILE_ASN1_TYPE_NUMERIC_STRING == 18
case $decoded['type'] > 30: // FILE_ASN1_TYPE_BMP_STRING == 30
case $mapping['type'] < 18:
case $mapping['type'] > 30:
return null;
}
}
if (isset($mapping['implicit'])) {
$decoded['type'] = $mapping['type'];
}
switch ($decoded['type']) {
case FILE_ASN1_TYPE_SEQUENCE:
$map = array();
// ignore the min and max
if (isset($mapping['min']) && isset($mapping['max'])) {
$child = $mapping['children'];
foreach ($decoded['content'] as $content) {
if (($map[] = $this->asn1map($content, $child, $special)) === null) {
return null;
}
}
return $map;
}
$n = count($decoded['content']);
$i = 0;
foreach ($mapping['children'] as $key => $child) {
$maymatch = $i < $n; // Match only existing input.
if ($maymatch) {
$temp = $decoded['content'][$i];
if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
// Get the mapping and input class & constant.
$childClass = $tempClass = FILE_ASN1_CLASS_UNIVERSAL;
$constant = null;
if (isset($temp['constant'])) {
$tempClass = $temp['type'];
}
if (isset($child['class'])) {
$childClass = $child['class'];
$constant = $child['cast'];
} elseif (isset($child['constant'])) {
$childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
$constant = $child['constant'];
}
if (isset($constant) && isset($temp['constant'])) {
// Can only match if constants and class match.
$maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
} else {
// Can only match if no constant expected and type matches or is generic.
$maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
}
}
}
if ($maymatch) {
// Attempt submapping.
$candidate = $this->asn1map($temp, $child, $special);
$maymatch = $candidate !== null;
}
if ($maymatch) {
// Got the match: use it.
if (isset($special[$key])) {
$candidate = call_user_func($special[$key], $candidate);
}
$map[$key] = $candidate;
$i++;
} elseif (isset($child['default'])) {
$map[$key] = $child['default']; // Use default.
} elseif (!isset($child['optional'])) {
return null; // Syntax error.
}
}
// Fail mapping if all input items have not been consumed.
return $i < $n ? null: $map;
// the main diff between sets and sequences is the encapsulation of the foreach in another for loop
case FILE_ASN1_TYPE_SET:
$map = array();
// ignore the min and max
if (isset($mapping['min']) && isset($mapping['max'])) {
$child = $mapping['children'];
foreach ($decoded['content'] as $content) {
if (($map[] = $this->asn1map($content, $child, $special)) === null) {
return null;
}
}
return $map;
}
for ($i = 0; $i < count($decoded['content']); $i++) {
$temp = $decoded['content'][$i];
$tempClass = FILE_ASN1_CLASS_UNIVERSAL;
if (isset($temp['constant'])) {
$tempClass = $temp['type'];
}
foreach ($mapping['children'] as $key => $child) {
if (isset($map[$key])) {
continue;
}
$maymatch = true;
if ($child['type'] != FILE_ASN1_TYPE_CHOICE) {
$childClass = FILE_ASN1_CLASS_UNIVERSAL;
$constant = null;
if (isset($child['class'])) {
$childClass = $child['class'];
$constant = $child['cast'];
} elseif (isset($child['constant'])) {
$childClass = FILE_ASN1_CLASS_CONTEXT_SPECIFIC;
$constant = $child['constant'];
}
if (isset($constant) && isset($temp['constant'])) {
// Can only match if constants and class match.
$maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
} else {
// Can only match if no constant expected and type matches or is generic.
$maymatch = !isset($child['constant']) && array_search($child['type'], array($temp['type'], FILE_ASN1_TYPE_ANY, FILE_ASN1_TYPE_CHOICE)) !== false;
}
}
if ($maymatch) {
// Attempt submapping.
$candidate = $this->asn1map($temp, $child, $special);
$maymatch = $candidate !== null;
}
if (!$maymatch) {
break;
}
// Got the match: use it.
if (isset($special[$key])) {
$candidate = call_user_func($special[$key], $candidate);
}
$map[$key] = $candidate;
break;
}
}
foreach ($mapping['children'] as $key => $child) {
if (!isset($map[$key])) {
if (isset($child['default'])) {
$map[$key] = $child['default'];
} elseif (!isset($child['optional'])) {
return null;
}
}
}
return $map;
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
case FILE_ASN1_TYPE_UTC_TIME:
case FILE_ASN1_TYPE_GENERALIZED_TIME:
if (class_exists('DateTime')) {
if (isset($mapping['implicit'])) {
$decoded['content'] = $this->_decodeDateTime($decoded['content'], $decoded['type']);
}
if (!$decoded['content']) {
return false;
}
return $decoded['content']->format($this->format);
} else {
if (isset($mapping['implicit'])) {
$decoded['content'] = $this->_decodeUnixTime($decoded['content'], $decoded['type']);
}
return @date($this->format, $decoded['content']);
}
case FILE_ASN1_TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
$offset = ord($decoded['content'][0]);
$size = (strlen($decoded['content']) - 1) * 8 - $offset;
/*
From X.680-0207.pdf#page=46 (21.7):
"When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove)
arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should
therefore ensure that different semantics are not associated with such values which differ only in the number of trailing
0 bits."
*/
$bits = count($mapping['mapping']) == $size ? array() : array_fill(0, count($mapping['mapping']) - $size, false);
for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
$current = ord($decoded['content'][$i]);
for ($j = $offset; $j < 8; $j++) {
$bits[] = (bool) ($current & (1 << $j));
}
$offset = 0;
}
$values = array();
$map = array_reverse($mapping['mapping']);
foreach ($map as $i => $value) {
if ($bits[$i]) {
$values[] = $value;
}
}
return $values;
}
case FILE_ASN1_TYPE_OCTET_STRING:
return base64_encode($decoded['content']);
case FILE_ASN1_TYPE_NULL:
return '';
case FILE_ASN1_TYPE_BOOLEAN:
return $decoded['content'];
case FILE_ASN1_TYPE_NUMERIC_STRING:
case FILE_ASN1_TYPE_PRINTABLE_STRING:
case FILE_ASN1_TYPE_TELETEX_STRING:
case FILE_ASN1_TYPE_VIDEOTEX_STRING:
case FILE_ASN1_TYPE_IA5_STRING:
case FILE_ASN1_TYPE_GRAPHIC_STRING:
case FILE_ASN1_TYPE_VISIBLE_STRING:
case FILE_ASN1_TYPE_GENERAL_STRING:
case FILE_ASN1_TYPE_UNIVERSAL_STRING:
case FILE_ASN1_TYPE_UTF8_STRING:
case FILE_ASN1_TYPE_BMP_STRING:
return $decoded['content'];
case FILE_ASN1_TYPE_INTEGER:
case FILE_ASN1_TYPE_ENUMERATED:
$temp = $decoded['content'];
if (isset($mapping['implicit'])) {
$temp = new Math_BigInteger($decoded['content'], -256);
}
if (isset($mapping['mapping'])) {
$temp = (int) $temp->toString();
return isset($mapping['mapping'][$temp]) ?
$mapping['mapping'][$temp] :
false;
}
return $temp;
}
}
/**
* ASN.1 Encode
*
* DER-encodes an ASN.1 semantic mapping ($mapping). Some libraries would probably call this function
* an ASN.1 compiler.
*
* "Special" mappings can be applied via $special.
*
* @param string $source
* @param string $mapping
* @param int $idx
* @return string
* @access public
*/
function encodeDER($source, $mapping, $special = array())
{
$this->location = array();
return $this->_encode_der($source, $mapping, null, $special);
}
/**
* ASN.1 Encode (Helper function)
*
* @param string $source
* @param string $mapping
* @param int $idx
* @return string
* @access private
*/
function _encode_der($source, $mapping, $idx = null, $special = array())
{
if (is_object($source) && strtolower(get_class($source)) == 'file_asn1_element') {
return $source->element;
}
// do not encode (implicitly optional) fields with value set to default
if (isset($mapping['default']) && $source === $mapping['default']) {
return '';
}
if (isset($idx)) {
if (isset($special[$idx])) {
$source = call_user_func($special[$idx], $source);
}
$this->location[] = $idx;
}
$tag = $mapping['type'];
switch ($tag) {
case FILE_ASN1_TYPE_SET: // Children order is not important, thus process in sequence.
case FILE_ASN1_TYPE_SEQUENCE:
$tag|= 0x20; // set the constructed bit
// ignore the min and max
if (isset($mapping['min']) && isset($mapping['max'])) {
$value = array();
$child = $mapping['children'];
foreach ($source as $content) {
$temp = $this->_encode_der($content, $child, null, $special);
if ($temp === false) {
return false;
}
$value[]= $temp;
}
/* "The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared
as octet strings with the shorter components being padded at their trailing end with 0-octets.
NOTE - The padding octets are for comparison purposes only and do not appear in the encodings."
-- sec 11.6 of http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf */
if ($mapping['type'] == FILE_ASN1_TYPE_SET) {
sort($value);
}
$value = implode($value, '');
break;
}
$value = '';
foreach ($mapping['children'] as $key => $child) {
if (!array_key_exists($key, $source)) {
if (!isset($child['optional'])) {
return false;
}
continue;
}
$temp = $this->_encode_der($source[$key], $child, $key, $special);
if ($temp === false) {
return false;
}
// An empty child encoding means it has been optimized out.
// Else we should have at least one tag byte.
if ($temp === '') {
continue;
}
// if isset($child['constant']) is true then isset($child['optional']) should be true as well
if (isset($child['constant'])) {
/*
From X.680-0207.pdf#page=58 (30.6):
"The tagging construction specifies explicit tagging if any of the following holds:
...
c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or
AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
*/
if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
$temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
} else {
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
$temp = $subtag . substr($temp, 1);
}
}
$value.= $temp;
}
break;
case FILE_ASN1_TYPE_CHOICE:
$temp = false;
foreach ($mapping['children'] as $key => $child) {
if (!isset($source[$key])) {
continue;
}
$temp = $this->_encode_der($source[$key], $child, $key, $special);
if ($temp === false) {
return false;
}
// An empty child encoding means it has been optimized out.
// Else we should have at least one tag byte.
if ($temp === '') {
continue;
}
$tag = ord($temp[0]);
// if isset($child['constant']) is true then isset($child['optional']) should be true as well
if (isset($child['constant'])) {
if (isset($child['explicit']) || $child['type'] == FILE_ASN1_TYPE_CHOICE) {
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
$temp = $subtag . $this->_encodeLength(strlen($temp)) . $temp;
} else {
$subtag = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
$temp = $subtag . substr($temp, 1);
}
}
}
if (isset($idx)) {
array_pop($this->location);
}
if ($temp && isset($mapping['cast'])) {
$temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
}
return $temp;
case FILE_ASN1_TYPE_INTEGER:
case FILE_ASN1_TYPE_ENUMERATED:
if (!isset($mapping['mapping'])) {
if (is_numeric($source)) {
$source = new Math_BigInteger($source);
}
$value = $source->toBytes(true);
} else {
$value = array_search($source, $mapping['mapping']);
if ($value === false) {
return false;
}
$value = new Math_BigInteger($value);
$value = $value->toBytes(true);
}
if (!strlen($value)) {
$value = chr(0);
}
break;
case FILE_ASN1_TYPE_UTC_TIME:
case FILE_ASN1_TYPE_GENERALIZED_TIME:
$format = $mapping['type'] == FILE_ASN1_TYPE_UTC_TIME ? 'y' : 'Y';
$format.= 'mdHis';
if (!class_exists('DateTime')) {
$value = @gmdate($format, strtotime($source)) . 'Z';
} else {
$date = new DateTime($source, new DateTimeZone('GMT'));
$value = $date->format($format) . 'Z';
}
break;
case FILE_ASN1_TYPE_BIT_STRING:
if (isset($mapping['mapping'])) {
$bits = array_fill(0, count($mapping['mapping']), 0);
$size = 0;
for ($i = 0; $i < count($mapping['mapping']); $i++) {
if (in_array($mapping['mapping'][$i], $source)) {
$bits[$i] = 1;
$size = $i;
}
}
if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) {
$size = $mapping['min'] - 1;
}
$offset = 8 - (($size + 1) & 7);
$offset = $offset !== 8 ? $offset : 0;
$value = chr($offset);
for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
unset($bits[$i]);
}
$bits = implode('', array_pad($bits, $size + $offset + 1, 0));
$bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
foreach ($bytes as $byte) {
$value.= chr(bindec($byte));
}
break;
}
case FILE_ASN1_TYPE_OCTET_STRING:
/* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven.
-- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
$value = base64_decode($source);
break;
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
if ($oid === false) {
user_error('Invalid OID');
return false;
}
$value = '';
$parts = explode('.', $oid);
$value = chr(40 * $parts[0] + $parts[1]);
for ($i = 2; $i < count($parts); $i++) {
$temp = '';
if (!$parts[$i]) {
$temp = "\0";
} else {
while ($parts[$i]) {
$temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
$parts[$i] >>= 7;
}
$temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
}
$value.= $temp;
}
break;
case FILE_ASN1_TYPE_ANY:
$loc = $this->location;
if (isset($idx)) {
array_pop($this->location);
}
switch (true) {
case !isset($source):
return $this->_encode_der(null, array('type' => FILE_ASN1_TYPE_NULL) + $mapping, null, $special);
case is_int($source):
case is_object($source) && strtolower(get_class($source)) == 'math_biginteger':
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_INTEGER) + $mapping, null, $special);
case is_float($source):
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_REAL) + $mapping, null, $special);
case is_bool($source):
return $this->_encode_der($source, array('type' => FILE_ASN1_TYPE_BOOLEAN) + $mapping, null, $special);
case is_array($source) && count($source) == 1:
$typename = implode('', array_keys($source));
$outtype = array_search($typename, $this->ANYmap, true);
if ($outtype !== false) {
return $this->_encode_der($source[$typename], array('type' => $outtype) + $mapping, null, $special);
}
}
$filters = $this->filters;
foreach ($loc as $part) {
if (!isset($filters[$part])) {
$filters = false;
break;
}
$filters = $filters[$part];
}
if ($filters === false) {
user_error('No filters defined for ' . implode('/', $loc));
return false;
}
return $this->_encode_der($source, $filters + $mapping, null, $special);
case FILE_ASN1_TYPE_NULL:
$value = '';
break;
case FILE_ASN1_TYPE_NUMERIC_STRING:
case FILE_ASN1_TYPE_TELETEX_STRING:
case FILE_ASN1_TYPE_PRINTABLE_STRING:
case FILE_ASN1_TYPE_UNIVERSAL_STRING:
case FILE_ASN1_TYPE_UTF8_STRING:
case FILE_ASN1_TYPE_BMP_STRING:
case FILE_ASN1_TYPE_IA5_STRING:
case FILE_ASN1_TYPE_VISIBLE_STRING:
case FILE_ASN1_TYPE_VIDEOTEX_STRING:
case FILE_ASN1_TYPE_GRAPHIC_STRING:
case FILE_ASN1_TYPE_GENERAL_STRING:
$value = $source;
break;
case FILE_ASN1_TYPE_BOOLEAN:
$value = $source ? "\xFF" : "\x00";
break;
default:
user_error('Mapping provides no type definition for ' . implode('/', $this->location));
return false;
}
if (isset($idx)) {
array_pop($this->location);
}
if (isset($mapping['cast'])) {
if (isset($mapping['explicit']) || $mapping['type'] == FILE_ASN1_TYPE_CHOICE) {
$value = chr($tag) . $this->_encodeLength(strlen($value)) . $value;
$tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast'];
} else {
$tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast'];
}
}
return chr($tag) . $this->_encodeLength(strlen($value)) . $value;
}
/**
* DER-encode the length
*
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
*
* @access private
* @param int $length
* @return string
*/
function _encodeLength($length)
{
if ($length <= 0x7F) {
return chr($length);
}
$temp = ltrim(pack('N', $length), chr(0));
return pack('Ca*', 0x80 | strlen($temp), $temp);
}
/**
* BER-decode the time (using UNIX time)
*
* Called by _decode_ber() and in the case of implicit tags asn1map().
*
* @access private
* @param string $content
* @param int $tag
* @return string
*/
function _decodeUnixTime($content, $tag)
{
/* UTCTime:
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
http://www.obj-sys.com/asn1tutorial/node15.html
GeneralizedTime:
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
http://www.obj-sys.com/asn1tutorial/node14.html */
$pattern = $tag == FILE_ASN1_TYPE_UTC_TIME ?
'#^(..)(..)(..)(..)(..)(..)?(.*)$#' :
'#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
preg_match($pattern, $content, $matches);
list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
$year = $year >= 50 ? "19$year" : "20$year";
}
if ($timezone == 'Z') {
$mktime = 'gmmktime';
$timezone = 0;
} elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
$mktime = 'gmmktime';
$timezone = 60 * $matches[3] + 3600 * $matches[2];
if ($matches[1] == '-') {
$timezone = -$timezone;
}
} else {
$mktime = 'mktime';
$timezone = 0;
}
return @$mktime((int)$hour, (int)$minute, (int)$second, (int)$month, (int)$day, (int)$year) + $timezone;
}
/**
* BER-decode the time (using DateTime)
*
* Called by _decode_ber() and in the case of implicit tags asn1map().
*
* @access private
* @param string $content
* @param int $tag
* @return string
*/
function _decodeDateTime($content, $tag)
{
/* UTCTime:
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
http://www.obj-sys.com/asn1tutorial/node15.html
GeneralizedTime:
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
http://www.obj-sys.com/asn1tutorial/node14.html */
$format = 'YmdHis';
if ($tag == FILE_ASN1_TYPE_UTC_TIME) {
// https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=28 says "the seconds
// element shall always be present" but none-the-less I've seen X509 certs where it isn't and if the
// browsers parse it phpseclib ought to too
if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) {
$content = $matches[1] . '00' . $matches[2];
}
$prefix = substr($content, 0, 2) >= 50 ? '19' : '20';
$content = $prefix . $content;
} elseif (strpos($content, '.') !== false) {
$format.= '.u';
}
if ($content[strlen($content) - 1] == 'Z') {
$content = substr($content, 0, -1) . '+0000';
}
if (strpos($content, '-') !== false || strpos($content, '+') !== false) {
$format.= 'O';
}
// error supression isn't necessary as of PHP 7.0:
// http://php.net/manual/en/migration70.other-changes.php
return @DateTime::createFromFormat($format, $content);
}
/**
* Set the time format
*
* Sets the time / date format for asn1map().
*
* @access public
* @param string $format
*/
function setTimeFormat($format)
{
$this->format = $format;
}
/**
* Load OIDs
*
* Load the relevant OIDs for a particular ASN.1 semantic mapping.
*
* @access public
* @param array $oids
*/
function loadOIDs($oids)
{
$this->oids = $oids;
}
/**
* Load filters
*
* See File_X509, etc, for an example.
*
* @access public
* @param array $filters
*/
function loadFilters($filters)
{
$this->filters = $filters;
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
/**
* String type conversion
*
* This is a lazy conversion, dealing only with character size.
* No real conversion table is used.
*
* @param string $in
* @param int $from
* @param int $to
* @return string
* @access public
*/
function convert($in, $from = FILE_ASN1_TYPE_UTF8_STRING, $to = FILE_ASN1_TYPE_UTF8_STRING)
{
if (!isset($this->stringTypeSize[$from]) || !isset($this->stringTypeSize[$to])) {
return false;
}
$insize = $this->stringTypeSize[$from];
$outsize = $this->stringTypeSize[$to];
$inlength = strlen($in);
$out = '';
for ($i = 0; $i < $inlength;) {
if ($inlength - $i < $insize) {
return false;
}
// Get an input character as a 32-bit value.
$c = ord($in[$i++]);
switch (true) {
case $insize == 4:
$c = ($c << 8) | ord($in[$i++]);
$c = ($c << 8) | ord($in[$i++]);
case $insize == 2:
$c = ($c << 8) | ord($in[$i++]);
case $insize == 1:
break;
case ($c & 0x80) == 0x00:
break;
case ($c & 0x40) == 0x00:
return false;
default:
$bit = 6;
do {
if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) {
return false;
}
$c = ($c << 6) | (ord($in[$i++]) & 0x3F);
$bit += 5;
$mask = 1 << $bit;
} while ($c & $bit);
$c &= $mask - 1;
break;
}
// Convert and append the character to output string.
$v = '';
switch (true) {
case $outsize == 4:
$v .= chr($c & 0xFF);
$c >>= 8;
$v .= chr($c & 0xFF);
$c >>= 8;
case $outsize == 2:
$v .= chr($c & 0xFF);
$c >>= 8;
case $outsize == 1:
$v .= chr($c & 0xFF);
$c >>= 8;
if ($c) {
return false;
}
break;
case ($c & 0x80000000) != 0:
return false;
case $c >= 0x04000000:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x04000000;
case $c >= 0x00200000:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x00200000;
case $c >= 0x00010000:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x00010000;
case $c >= 0x00000800:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x00000800;
case $c >= 0x00000080:
$v .= chr(0x80 | ($c & 0x3F));
$c = ($c >> 6) | 0x000000C0;
default:
$v .= chr($c);
break;
}
$out .= strrev($v);
}
return $out;
}
}
================================================
FILE: assets/libraries/phpseclib/File/X509.php
================================================
* @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include File_ASN1
*/
if (!class_exists('File_ASN1')) {
include_once 'ASN1.php';
}
/**
* Flag to only accept signatures signed by certificate authorities
*
* Not really used anymore but retained all the same to suppress E_NOTICEs from old installs
*
* @access public
*/
define('FILE_X509_VALIDATE_SIGNATURE_BY_CA', 1);
/**#@+
* @access public
* @see self::getDN()
*/
/**
* Return internal array representation
*/
define('FILE_X509_DN_ARRAY', 0);
/**
* Return string
*/
define('FILE_X509_DN_STRING', 1);
/**
* Return ASN.1 name string
*/
define('FILE_X509_DN_ASN1', 2);
/**
* Return OpenSSL compatible array
*/
define('FILE_X509_DN_OPENSSL', 3);
/**
* Return canonical ASN.1 RDNs string
*/
define('FILE_X509_DN_CANON', 4);
/**
* Return name hash for file indexing
*/
define('FILE_X509_DN_HASH', 5);
/**#@-*/
/**#@+
* @access public
* @see self::saveX509()
* @see self::saveCSR()
* @see self::saveCRL()
*/
/**
* Save as PEM
*
* ie. a base64-encoded PEM with a header and a footer
*/
define('FILE_X509_FORMAT_PEM', 0);
/**
* Save as DER
*/
define('FILE_X509_FORMAT_DER', 1);
/**
* Save as a SPKAC
*
* Only works on CSRs. Not currently supported.
*/
define('FILE_X509_FORMAT_SPKAC', 2);
/**
* Auto-detect the format
*
* Used only by the load*() functions
*/
define('FILE_X509_FORMAT_AUTO_DETECT', 3);
/**#@-*/
/**
* Attribute value disposition.
* If disposition is >= 0, this is the index of the target value.
*/
define('FILE_X509_ATTR_ALL', -1); // All attribute values (array).
define('FILE_X509_ATTR_APPEND', -2); // Add a value.
define('FILE_X509_ATTR_REPLACE', -3); // Clear first, then add a value.
/**
* Pure-PHP X.509 Parser
*
* @package File_X509
* @author Jim Wigginton
* @access public
*/
class File_X509
{
/**
* ASN.1 syntax for X.509 certificates
*
* @var array
* @access private
*/
var $Certificate;
/**#@+
* ASN.1 syntax for various extensions
*
* @access private
*/
var $DirectoryString;
var $PKCS9String;
var $AttributeValue;
var $Extensions;
var $KeyUsage;
var $ExtKeyUsageSyntax;
var $BasicConstraints;
var $KeyIdentifier;
var $CRLDistributionPoints;
var $AuthorityKeyIdentifier;
var $CertificatePolicies;
var $AuthorityInfoAccessSyntax;
var $SubjectAltName;
var $SubjectDirectoryAttributes;
var $PrivateKeyUsagePeriod;
var $IssuerAltName;
var $PolicyMappings;
var $NameConstraints;
var $CPSuri;
var $UserNotice;
var $netscape_cert_type;
var $netscape_comment;
var $netscape_ca_policy_url;
var $Name;
var $RelativeDistinguishedName;
var $CRLNumber;
var $CRLReason;
var $IssuingDistributionPoint;
var $InvalidityDate;
var $CertificateIssuer;
var $HoldInstructionCode;
var $SignedPublicKeyAndChallenge;
/**#@-*/
/**#@+
* ASN.1 syntax for various DN attributes
*
* @access private
*/
var $PostalAddress;
/**#@-*/
/**
* ASN.1 syntax for Certificate Signing Requests (RFC2986)
*
* @var array
* @access private
*/
var $CertificationRequest;
/**
* ASN.1 syntax for Certificate Revocation Lists (RFC5280)
*
* @var array
* @access private
*/
var $CertificateList;
/**
* Distinguished Name
*
* @var array
* @access private
*/
var $dn;
/**
* Public key
*
* @var string
* @access private
*/
var $publicKey;
/**
* Private key
*
* @var string
* @access private
*/
var $privateKey;
/**
* Object identifiers for X.509 certificates
*
* @var array
* @access private
* @link http://en.wikipedia.org/wiki/Object_identifier
*/
var $oids;
/**
* The certificate authorities
*
* @var array
* @access private
*/
var $CAs;
/**
* The currently loaded certificate
*
* @var array
* @access private
*/
var $currentCert;
/**
* The signature subject
*
* There's no guarantee File_X509 is going to re-encode an X.509 cert in the same way it was originally
* encoded so we take save the portion of the original cert that the signature would have made for.
*
* @var string
* @access private
*/
var $signatureSubject;
/**
* Certificate Start Date
*
* @var string
* @access private
*/
var $startDate;
/**
* Certificate End Date
*
* @var string
* @access private
*/
var $endDate;
/**
* Serial Number
*
* @var string
* @access private
*/
var $serialNumber;
/**
* Key Identifier
*
* See {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.1 RFC5280#section-4.2.1.1} and
* {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.2 RFC5280#section-4.2.1.2}.
*
* @var string
* @access private
*/
var $currentKeyIdentifier;
/**
* CA Flag
*
* @var bool
* @access private
*/
var $caFlag = false;
/**
* SPKAC Challenge
*
* @var string
* @access private
*/
var $challenge;
/**
* Recursion Limit
*
* @var int
* @access private
*/
var $recur_limit = 5;
/**
* URL fetch flag
*
* @var bool
* @access private
*/
var $disable_url_fetch = false;
/**
* Default Constructor.
*
* @return File_X509
* @access public
*/
function __construct()
{
if (!class_exists('Math_BigInteger')) {
include_once 'Math/BigInteger.php';
}
// Explicitly Tagged Module, 1988 Syntax
// http://tools.ietf.org/html/rfc5280#appendix-A.1
$this->DirectoryString = array(
'type' => FILE_ASN1_TYPE_CHOICE,
'children' => array(
'teletexString' => array('type' => FILE_ASN1_TYPE_TELETEX_STRING),
'printableString' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING),
'universalString' => array('type' => FILE_ASN1_TYPE_UNIVERSAL_STRING),
'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING),
'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING)
)
);
$this->PKCS9String = array(
'type' => FILE_ASN1_TYPE_CHOICE,
'children' => array(
'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING),
'directoryString' => $this->DirectoryString
)
);
$this->AttributeValue = array('type' => FILE_ASN1_TYPE_ANY);
$AttributeType = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
$AttributeTypeAndValue = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'type' => $AttributeType,
'value'=> $this->AttributeValue
)
);
/*
In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare,
but they can be useful at times when either there is no unique attribute in the entry or you
want to ensure that the entry's DN contains some useful identifying information.
- https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName
*/
$this->RelativeDistinguishedName = array(
'type' => FILE_ASN1_TYPE_SET,
'min' => 1,
'max' => -1,
'children' => $AttributeTypeAndValue
);
// http://tools.ietf.org/html/rfc5280#section-4.1.2.4
$RDNSequence = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
// RDNSequence does not define a min or a max, which means it doesn't have one
'min' => 0,
'max' => -1,
'children' => $this->RelativeDistinguishedName
);
$this->Name = array(
'type' => FILE_ASN1_TYPE_CHOICE,
'children' => array(
'rdnSequence' => $RDNSequence
)
);
// http://tools.ietf.org/html/rfc5280#section-4.1.1.2
$AlgorithmIdentifier = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'algorithm' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
'parameters' => array(
'type' => FILE_ASN1_TYPE_ANY,
'optional' => true
)
)
);
/*
A certificate using system MUST reject the certificate if it encounters
a critical extension it does not recognize; however, a non-critical
extension may be ignored if it is not recognized.
http://tools.ietf.org/html/rfc5280#section-4.2
*/
$Extension = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'extnId' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
'critical' => array(
'type' => FILE_ASN1_TYPE_BOOLEAN,
'optional' => true,
'default' => false
),
'extnValue' => array('type' => FILE_ASN1_TYPE_OCTET_STRING)
)
);
$this->Extensions = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
// technically, it's MAX, but we'll assume anything < 0 is MAX
'max' => -1,
// if 'children' isn't an array then 'min' and 'max' must be defined
'children' => $Extension
);
$SubjectPublicKeyInfo = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'algorithm' => $AlgorithmIdentifier,
'subjectPublicKey' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
)
);
$UniqueIdentifier = array('type' => FILE_ASN1_TYPE_BIT_STRING);
$Time = array(
'type' => FILE_ASN1_TYPE_CHOICE,
'children' => array(
'utcTime' => array('type' => FILE_ASN1_TYPE_UTC_TIME),
'generalTime' => array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME)
)
);
// http://tools.ietf.org/html/rfc5280#section-4.1.2.5
$Validity = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'notBefore' => $Time,
'notAfter' => $Time
)
);
$CertificateSerialNumber = array('type' => FILE_ASN1_TYPE_INTEGER);
$Version = array(
'type' => FILE_ASN1_TYPE_INTEGER,
'mapping' => array('v1', 'v2', 'v3')
);
// assert($TBSCertificate['children']['signature'] == $Certificate['children']['signatureAlgorithm'])
$TBSCertificate = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
// technically, default implies optional, but we'll define it as being optional, none-the-less, just to
// reenforce that fact
'version' => array(
'constant' => 0,
'optional' => true,
'explicit' => true,
'default' => 'v1'
) + $Version,
'serialNumber' => $CertificateSerialNumber,
'signature' => $AlgorithmIdentifier,
'issuer' => $this->Name,
'validity' => $Validity,
'subject' => $this->Name,
'subjectPublicKeyInfo' => $SubjectPublicKeyInfo,
// implicit means that the T in the TLV structure is to be rewritten, regardless of the type
'issuerUniqueID' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $UniqueIdentifier,
'subjectUniqueID' => array(
'constant' => 2,
'optional' => true,
'implicit' => true
) + $UniqueIdentifier,
// doesn't use the EXPLICIT keyword but if
// it's not IMPLICIT, it's EXPLICIT
'extensions' => array(
'constant' => 3,
'optional' => true,
'explicit' => true
) + $this->Extensions
)
);
$this->Certificate = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'tbsCertificate' => $TBSCertificate,
'signatureAlgorithm' => $AlgorithmIdentifier,
'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
)
);
$this->KeyUsage = array(
'type' => FILE_ASN1_TYPE_BIT_STRING,
'mapping' => array(
'digitalSignature',
'nonRepudiation',
'keyEncipherment',
'dataEncipherment',
'keyAgreement',
'keyCertSign',
'cRLSign',
'encipherOnly',
'decipherOnly'
)
);
$this->BasicConstraints = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'cA' => array(
'type' => FILE_ASN1_TYPE_BOOLEAN,
'optional' => true,
'default' => false
),
'pathLenConstraint' => array(
'type' => FILE_ASN1_TYPE_INTEGER,
'optional' => true
)
)
);
$this->KeyIdentifier = array('type' => FILE_ASN1_TYPE_OCTET_STRING);
$OrganizationalUnitNames = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
'max' => 4, // ub-organizational-units
'children' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
);
$PersonalName = array(
'type' => FILE_ASN1_TYPE_SET,
'children' => array(
'surname' => array(
'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
'constant' => 0,
'optional' => true,
'implicit' => true
),
'given-name' => array(
'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
'constant' => 1,
'optional' => true,
'implicit' => true
),
'initials' => array(
'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
'constant' => 2,
'optional' => true,
'implicit' => true
),
'generation-qualifier' => array(
'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
'constant' => 3,
'optional' => true,
'implicit' => true
)
)
);
$NumericUserIdentifier = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING);
$OrganizationName = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING);
$PrivateDomainName = array(
'type' => FILE_ASN1_TYPE_CHOICE,
'children' => array(
'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
)
);
$TerminalIdentifier = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING);
$NetworkAddress = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING);
$AdministrationDomainName = array(
'type' => FILE_ASN1_TYPE_CHOICE,
// if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or
// (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC
'class' => FILE_ASN1_CLASS_APPLICATION,
'cast' => 2,
'children' => array(
'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
)
);
$CountryName = array(
'type' => FILE_ASN1_TYPE_CHOICE,
// if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or
// (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC
'class' => FILE_ASN1_CLASS_APPLICATION,
'cast' => 1,
'children' => array(
'x121-dcc-code' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING),
'iso-3166-alpha2-code' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
)
);
$AnotherName = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'type-id' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
'value' => array(
'type' => FILE_ASN1_TYPE_ANY,
'constant' => 0,
'optional' => true,
'explicit' => true
)
)
);
$ExtensionAttribute = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'extension-attribute-type' => array(
'type' => FILE_ASN1_TYPE_PRINTABLE_STRING,
'constant' => 0,
'optional' => true,
'implicit' => true
),
'extension-attribute-value' => array(
'type' => FILE_ASN1_TYPE_ANY,
'constant' => 1,
'optional' => true,
'explicit' => true
)
)
);
$ExtensionAttributes = array(
'type' => FILE_ASN1_TYPE_SET,
'min' => 1,
'max' => 256, // ub-extension-attributes
'children' => $ExtensionAttribute
);
$BuiltInDomainDefinedAttribute = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'type' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING),
'value' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING)
)
);
$BuiltInDomainDefinedAttributes = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
'max' => 4, // ub-domain-defined-attributes
'children' => $BuiltInDomainDefinedAttribute
);
$BuiltInStandardAttributes = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'country-name' => array('optional' => true) + $CountryName,
'administration-domain-name' => array('optional' => true) + $AdministrationDomainName,
'network-address' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $NetworkAddress,
'terminal-identifier' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $TerminalIdentifier,
'private-domain-name' => array(
'constant' => 2,
'optional' => true,
'explicit' => true
) + $PrivateDomainName,
'organization-name' => array(
'constant' => 3,
'optional' => true,
'implicit' => true
) + $OrganizationName,
'numeric-user-identifier' => array(
'constant' => 4,
'optional' => true,
'implicit' => true
) + $NumericUserIdentifier,
'personal-name' => array(
'constant' => 5,
'optional' => true,
'implicit' => true
) + $PersonalName,
'organizational-unit-names' => array(
'constant' => 6,
'optional' => true,
'implicit' => true
) + $OrganizationalUnitNames
)
);
$ORAddress = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'built-in-standard-attributes' => $BuiltInStandardAttributes,
'built-in-domain-defined-attributes' => array('optional' => true) + $BuiltInDomainDefinedAttributes,
'extension-attributes' => array('optional' => true) + $ExtensionAttributes
)
);
$EDIPartyName = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'nameAssigner' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $this->DirectoryString,
// partyName is technically required but File_ASN1 doesn't currently support non-optional constants and
// setting it to optional gets the job done in any event.
'partyName' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $this->DirectoryString
)
);
$GeneralName = array(
'type' => FILE_ASN1_TYPE_CHOICE,
'children' => array(
'otherName' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $AnotherName,
'rfc822Name' => array(
'type' => FILE_ASN1_TYPE_IA5_STRING,
'constant' => 1,
'optional' => true,
'implicit' => true
),
'dNSName' => array(
'type' => FILE_ASN1_TYPE_IA5_STRING,
'constant' => 2,
'optional' => true,
'implicit' => true
),
'x400Address' => array(
'constant' => 3,
'optional' => true,
'implicit' => true
) + $ORAddress,
'directoryName' => array(
'constant' => 4,
'optional' => true,
'explicit' => true
) + $this->Name,
'ediPartyName' => array(
'constant' => 5,
'optional' => true,
'implicit' => true
) + $EDIPartyName,
'uniformResourceIdentifier' => array(
'type' => FILE_ASN1_TYPE_IA5_STRING,
'constant' => 6,
'optional' => true,
'implicit' => true
),
'iPAddress' => array(
'type' => FILE_ASN1_TYPE_OCTET_STRING,
'constant' => 7,
'optional' => true,
'implicit' => true
),
'registeredID' => array(
'type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER,
'constant' => 8,
'optional' => true,
'implicit' => true
)
)
);
$GeneralNames = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $GeneralName
);
$this->IssuerAltName = $GeneralNames;
$ReasonFlags = array(
'type' => FILE_ASN1_TYPE_BIT_STRING,
'mapping' => array(
'unused',
'keyCompromise',
'cACompromise',
'affiliationChanged',
'superseded',
'cessationOfOperation',
'certificateHold',
'privilegeWithdrawn',
'aACompromise'
)
);
$DistributionPointName = array(
'type' => FILE_ASN1_TYPE_CHOICE,
'children' => array(
'fullName' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $GeneralNames,
'nameRelativeToCRLIssuer' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $this->RelativeDistinguishedName
)
);
$DistributionPoint = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'distributionPoint' => array(
'constant' => 0,
'optional' => true,
'explicit' => true
) + $DistributionPointName,
'reasons' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $ReasonFlags,
'cRLIssuer' => array(
'constant' => 2,
'optional' => true,
'implicit' => true
) + $GeneralNames
)
);
$this->CRLDistributionPoints = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $DistributionPoint
);
$this->AuthorityKeyIdentifier = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'keyIdentifier' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $this->KeyIdentifier,
'authorityCertIssuer' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $GeneralNames,
'authorityCertSerialNumber' => array(
'constant' => 2,
'optional' => true,
'implicit' => true
) + $CertificateSerialNumber
)
);
$PolicyQualifierId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
$PolicyQualifierInfo = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'policyQualifierId' => $PolicyQualifierId,
'qualifier' => array('type' => FILE_ASN1_TYPE_ANY)
)
);
$CertPolicyId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
$PolicyInformation = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'policyIdentifier' => $CertPolicyId,
'policyQualifiers' => array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 0,
'max' => -1,
'optional' => true,
'children' => $PolicyQualifierInfo
)
)
);
$this->CertificatePolicies = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $PolicyInformation
);
$this->PolicyMappings = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'issuerDomainPolicy' => $CertPolicyId,
'subjectDomainPolicy' => $CertPolicyId
)
)
);
$KeyPurposeId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
$this->ExtKeyUsageSyntax = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $KeyPurposeId
);
$AccessDescription = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'accessMethod' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER),
'accessLocation' => $GeneralName
)
);
$this->AuthorityInfoAccessSyntax = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $AccessDescription
);
$this->SubjectAltName = $GeneralNames;
$this->PrivateKeyUsagePeriod = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'notBefore' => array(
'constant' => 0,
'optional' => true,
'implicit' => true,
'type' => FILE_ASN1_TYPE_GENERALIZED_TIME),
'notAfter' => array(
'constant' => 1,
'optional' => true,
'implicit' => true,
'type' => FILE_ASN1_TYPE_GENERALIZED_TIME)
)
);
$BaseDistance = array('type' => FILE_ASN1_TYPE_INTEGER);
$GeneralSubtree = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'base' => $GeneralName,
'minimum' => array(
'constant' => 0,
'optional' => true,
'implicit' => true,
'default' => new Math_BigInteger(0)
) + $BaseDistance,
'maximum' => array(
'constant' => 1,
'optional' => true,
'implicit' => true,
) + $BaseDistance
)
);
$GeneralSubtrees = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $GeneralSubtree
);
$this->NameConstraints = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'permittedSubtrees' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $GeneralSubtrees,
'excludedSubtrees' => array(
'constant' => 1,
'optional' => true,
'implicit' => true
) + $GeneralSubtrees
)
);
$this->CPSuri = array('type' => FILE_ASN1_TYPE_IA5_STRING);
$DisplayText = array(
'type' => FILE_ASN1_TYPE_CHOICE,
'children' => array(
'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING),
'visibleString' => array('type' => FILE_ASN1_TYPE_VISIBLE_STRING),
'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING),
'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING)
)
);
$NoticeReference = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'organization' => $DisplayText,
'noticeNumbers' => array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
'max' => 200,
'children' => array('type' => FILE_ASN1_TYPE_INTEGER)
)
)
);
$this->UserNotice = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'noticeRef' => array(
'optional' => true,
'implicit' => true
) + $NoticeReference,
'explicitText' => array(
'optional' => true,
'implicit' => true
) + $DisplayText
)
);
// mapping is from
$this->netscape_cert_type = array(
'type' => FILE_ASN1_TYPE_BIT_STRING,
'mapping' => array(
'SSLClient',
'SSLServer',
'Email',
'ObjectSigning',
'Reserved',
'SSLCA',
'EmailCA',
'ObjectSigningCA'
)
);
$this->netscape_comment = array('type' => FILE_ASN1_TYPE_IA5_STRING);
$this->netscape_ca_policy_url = array('type' => FILE_ASN1_TYPE_IA5_STRING);
// attribute is used in RFC2986 but we're using the RFC5280 definition
$Attribute = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'type' => $AttributeType,
'value'=> array(
'type' => FILE_ASN1_TYPE_SET,
'min' => 1,
'max' => -1,
'children' => $this->AttributeValue
)
)
);
$this->SubjectDirectoryAttributes = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $Attribute
);
// adapted from
$Attributes = array(
'type' => FILE_ASN1_TYPE_SET,
'min' => 1,
'max' => -1,
'children' => $Attribute
);
$CertificationRequestInfo = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'version' => array(
'type' => FILE_ASN1_TYPE_INTEGER,
'mapping' => array('v1')
),
'subject' => $this->Name,
'subjectPKInfo' => $SubjectPublicKeyInfo,
'attributes' => array(
'constant' => 0,
'optional' => true,
'implicit' => true
) + $Attributes,
)
);
$this->CertificationRequest = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'certificationRequestInfo' => $CertificationRequestInfo,
'signatureAlgorithm' => $AlgorithmIdentifier,
'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
)
);
$RevokedCertificate = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'userCertificate' => $CertificateSerialNumber,
'revocationDate' => $Time,
'crlEntryExtensions' => array(
'optional' => true
) + $this->Extensions
)
);
$TBSCertList = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'version' => array(
'optional' => true,
'default' => 'v1'
) + $Version,
'signature' => $AlgorithmIdentifier,
'issuer' => $this->Name,
'thisUpdate' => $Time,
'nextUpdate' => array(
'optional' => true
) + $Time,
'revokedCertificates' => array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'optional' => true,
'min' => 0,
'max' => -1,
'children' => $RevokedCertificate
),
'crlExtensions' => array(
'constant' => 0,
'optional' => true,
'explicit' => true
) + $this->Extensions
)
);
$this->CertificateList = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'tbsCertList' => $TBSCertList,
'signatureAlgorithm' => $AlgorithmIdentifier,
'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
)
);
$this->CRLNumber = array('type' => FILE_ASN1_TYPE_INTEGER);
$this->CRLReason = array('type' => FILE_ASN1_TYPE_ENUMERATED,
'mapping' => array(
'unspecified',
'keyCompromise',
'cACompromise',
'affiliationChanged',
'superseded',
'cessationOfOperation',
'certificateHold',
// Value 7 is not used.
8 => 'removeFromCRL',
'privilegeWithdrawn',
'aACompromise'
)
);
$this->IssuingDistributionPoint = array('type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'distributionPoint' => array(
'constant' => 0,
'optional' => true,
'explicit' => true
) + $DistributionPointName,
'onlyContainsUserCerts' => array(
'type' => FILE_ASN1_TYPE_BOOLEAN,
'constant' => 1,
'optional' => true,
'default' => false,
'implicit' => true
),
'onlyContainsCACerts' => array(
'type' => FILE_ASN1_TYPE_BOOLEAN,
'constant' => 2,
'optional' => true,
'default' => false,
'implicit' => true
),
'onlySomeReasons' => array(
'constant' => 3,
'optional' => true,
'implicit' => true
) + $ReasonFlags,
'indirectCRL' => array(
'type' => FILE_ASN1_TYPE_BOOLEAN,
'constant' => 4,
'optional' => true,
'default' => false,
'implicit' => true
),
'onlyContainsAttributeCerts' => array(
'type' => FILE_ASN1_TYPE_BOOLEAN,
'constant' => 5,
'optional' => true,
'default' => false,
'implicit' => true
)
)
);
$this->InvalidityDate = array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME);
$this->CertificateIssuer = $GeneralNames;
$this->HoldInstructionCode = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER);
$PublicKeyAndChallenge = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'spki' => $SubjectPublicKeyInfo,
'challenge' => array('type' => FILE_ASN1_TYPE_IA5_STRING)
)
);
$this->SignedPublicKeyAndChallenge = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'children' => array(
'publicKeyAndChallenge' => $PublicKeyAndChallenge,
'signatureAlgorithm' => $AlgorithmIdentifier,
'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING)
)
);
$this->PostalAddress = array(
'type' => FILE_ASN1_TYPE_SEQUENCE,
'optional' => true,
'min' => 1,
'max' => -1,
'children' => $this->DirectoryString
);
// OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2
$this->oids = array(
'1.3.6.1.5.5.7' => 'id-pkix',
'1.3.6.1.5.5.7.1' => 'id-pe',
'1.3.6.1.5.5.7.2' => 'id-qt',
'1.3.6.1.5.5.7.3' => 'id-kp',
'1.3.6.1.5.5.7.48' => 'id-ad',
'1.3.6.1.5.5.7.2.1' => 'id-qt-cps',
'1.3.6.1.5.5.7.2.2' => 'id-qt-unotice',
'1.3.6.1.5.5.7.48.1' =>'id-ad-ocsp',
'1.3.6.1.5.5.7.48.2' => 'id-ad-caIssuers',
'1.3.6.1.5.5.7.48.3' => 'id-ad-timeStamping',
'1.3.6.1.5.5.7.48.5' => 'id-ad-caRepository',
'2.5.4' => 'id-at',
'2.5.4.41' => 'id-at-name',
'2.5.4.4' => 'id-at-surname',
'2.5.4.42' => 'id-at-givenName',
'2.5.4.43' => 'id-at-initials',
'2.5.4.44' => 'id-at-generationQualifier',
'2.5.4.3' => 'id-at-commonName',
'2.5.4.7' => 'id-at-localityName',
'2.5.4.8' => 'id-at-stateOrProvinceName',
'2.5.4.10' => 'id-at-organizationName',
'2.5.4.11' => 'id-at-organizationalUnitName',
'2.5.4.12' => 'id-at-title',
'2.5.4.13' => 'id-at-description',
'2.5.4.46' => 'id-at-dnQualifier',
'2.5.4.6' => 'id-at-countryName',
'2.5.4.5' => 'id-at-serialNumber',
'2.5.4.65' => 'id-at-pseudonym',
'2.5.4.17' => 'id-at-postalCode',
'2.5.4.9' => 'id-at-streetAddress',
'2.5.4.45' => 'id-at-uniqueIdentifier',
'2.5.4.72' => 'id-at-role',
'2.5.4.16' => 'id-at-postalAddress',
'0.9.2342.19200300.100.1.25' => 'id-domainComponent',
'1.2.840.113549.1.9' => 'pkcs-9',
'1.2.840.113549.1.9.1' => 'pkcs-9-at-emailAddress',
'2.5.29' => 'id-ce',
'2.5.29.35' => 'id-ce-authorityKeyIdentifier',
'2.5.29.14' => 'id-ce-subjectKeyIdentifier',
'2.5.29.15' => 'id-ce-keyUsage',
'2.5.29.16' => 'id-ce-privateKeyUsagePeriod',
'2.5.29.32' => 'id-ce-certificatePolicies',
'2.5.29.32.0' => 'anyPolicy',
'2.5.29.33' => 'id-ce-policyMappings',
'2.5.29.17' => 'id-ce-subjectAltName',
'2.5.29.18' => 'id-ce-issuerAltName',
'2.5.29.9' => 'id-ce-subjectDirectoryAttributes',
'2.5.29.19' => 'id-ce-basicConstraints',
'2.5.29.30' => 'id-ce-nameConstraints',
'2.5.29.36' => 'id-ce-policyConstraints',
'2.5.29.31' => 'id-ce-cRLDistributionPoints',
'2.5.29.37' => 'id-ce-extKeyUsage',
'2.5.29.37.0' => 'anyExtendedKeyUsage',
'1.3.6.1.5.5.7.3.1' => 'id-kp-serverAuth',
'1.3.6.1.5.5.7.3.2' => 'id-kp-clientAuth',
'1.3.6.1.5.5.7.3.3' => 'id-kp-codeSigning',
'1.3.6.1.5.5.7.3.4' => 'id-kp-emailProtection',
'1.3.6.1.5.5.7.3.8' => 'id-kp-timeStamping',
'1.3.6.1.5.5.7.3.9' => 'id-kp-OCSPSigning',
'2.5.29.54' => 'id-ce-inhibitAnyPolicy',
'2.5.29.46' => 'id-ce-freshestCRL',
'1.3.6.1.5.5.7.1.1' => 'id-pe-authorityInfoAccess',
'1.3.6.1.5.5.7.1.11' => 'id-pe-subjectInfoAccess',
'2.5.29.20' => 'id-ce-cRLNumber',
'2.5.29.28' => 'id-ce-issuingDistributionPoint',
'2.5.29.27' => 'id-ce-deltaCRLIndicator',
'2.5.29.21' => 'id-ce-cRLReasons',
'2.5.29.29' => 'id-ce-certificateIssuer',
'2.5.29.23' => 'id-ce-holdInstructionCode',
'1.2.840.10040.2' => 'holdInstruction',
'1.2.840.10040.2.1' => 'id-holdinstruction-none',
'1.2.840.10040.2.2' => 'id-holdinstruction-callissuer',
'1.2.840.10040.2.3' => 'id-holdinstruction-reject',
'2.5.29.24' => 'id-ce-invalidityDate',
'1.2.840.113549.2.2' => 'md2',
'1.2.840.113549.2.5' => 'md5',
'1.3.14.3.2.26' => 'id-sha1',
'1.2.840.10040.4.1' => 'id-dsa',
'1.2.840.10040.4.3' => 'id-dsa-with-sha1',
'1.2.840.113549.1.1' => 'pkcs-1',
'1.2.840.113549.1.1.1' => 'rsaEncryption',
'1.2.840.113549.1.1.2' => 'md2WithRSAEncryption',
'1.2.840.113549.1.1.4' => 'md5WithRSAEncryption',
'1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption',
'1.2.840.10046.2.1' => 'dhpublicnumber',
'2.16.840.1.101.2.1.1.22' => 'id-keyExchangeAlgorithm',
'1.2.840.10045' => 'ansi-X9-62',
'1.2.840.10045.4' => 'id-ecSigType',
'1.2.840.10045.4.1' => 'ecdsa-with-SHA1',
'1.2.840.10045.1' => 'id-fieldType',
'1.2.840.10045.1.1' => 'prime-field',
'1.2.840.10045.1.2' => 'characteristic-two-field',
'1.2.840.10045.1.2.3' => 'id-characteristic-two-basis',
'1.2.840.10045.1.2.3.1' => 'gnBasis',
'1.2.840.10045.1.2.3.2' => 'tpBasis',
'1.2.840.10045.1.2.3.3' => 'ppBasis',
'1.2.840.10045.2' => 'id-publicKeyType',
'1.2.840.10045.2.1' => 'id-ecPublicKey',
'1.2.840.10045.3' => 'ellipticCurve',
'1.2.840.10045.3.0' => 'c-TwoCurve',
'1.2.840.10045.3.0.1' => 'c2pnb163v1',
'1.2.840.10045.3.0.2' => 'c2pnb163v2',
'1.2.840.10045.3.0.3' => 'c2pnb163v3',
'1.2.840.10045.3.0.4' => 'c2pnb176w1',
'1.2.840.10045.3.0.5' => 'c2pnb191v1',
'1.2.840.10045.3.0.6' => 'c2pnb191v2',
'1.2.840.10045.3.0.7' => 'c2pnb191v3',
'1.2.840.10045.3.0.8' => 'c2pnb191v4',
'1.2.840.10045.3.0.9' => 'c2pnb191v5',
'1.2.840.10045.3.0.10' => 'c2pnb208w1',
'1.2.840.10045.3.0.11' => 'c2pnb239v1',
'1.2.840.10045.3.0.12' => 'c2pnb239v2',
'1.2.840.10045.3.0.13' => 'c2pnb239v3',
'1.2.840.10045.3.0.14' => 'c2pnb239v4',
'1.2.840.10045.3.0.15' => 'c2pnb239v5',
'1.2.840.10045.3.0.16' => 'c2pnb272w1',
'1.2.840.10045.3.0.17' => 'c2pnb304w1',
'1.2.840.10045.3.0.18' => 'c2pnb359v1',
'1.2.840.10045.3.0.19' => 'c2pnb368w1',
'1.2.840.10045.3.0.20' => 'c2pnb431r1',
'1.2.840.10045.3.1' => 'primeCurve',
'1.2.840.10045.3.1.1' => 'prime192v1',
'1.2.840.10045.3.1.2' => 'prime192v2',
'1.2.840.10045.3.1.3' => 'prime192v3',
'1.2.840.10045.3.1.4' => 'prime239v1',
'1.2.840.10045.3.1.5' => 'prime239v2',
'1.2.840.10045.3.1.6' => 'prime239v3',
'1.2.840.10045.3.1.7' => 'prime256v1',
'1.2.840.113549.1.1.7' => 'id-RSAES-OAEP',
'1.2.840.113549.1.1.9' => 'id-pSpecified',
'1.2.840.113549.1.1.10' => 'id-RSASSA-PSS',
'1.2.840.113549.1.1.8' => 'id-mgf1',
'1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption',
'1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption',
'1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption',
'1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption',
'2.16.840.1.101.3.4.2.4' => 'id-sha224',
'2.16.840.1.101.3.4.2.1' => 'id-sha256',
'2.16.840.1.101.3.4.2.2' => 'id-sha384',
'2.16.840.1.101.3.4.2.3' => 'id-sha512',
'1.2.643.2.2.4' => 'id-GostR3411-94-with-GostR3410-94',
'1.2.643.2.2.3' => 'id-GostR3411-94-with-GostR3410-2001',
'1.2.643.2.2.20' => 'id-GostR3410-2001',
'1.2.643.2.2.19' => 'id-GostR3410-94',
// Netscape Object Identifiers from "Netscape Certificate Extensions"
'2.16.840.1.113730' => 'netscape',
'2.16.840.1.113730.1' => 'netscape-cert-extension',
'2.16.840.1.113730.1.1' => 'netscape-cert-type',
'2.16.840.1.113730.1.13' => 'netscape-comment',
'2.16.840.1.113730.1.8' => 'netscape-ca-policy-url',
// the following are X.509 extensions not supported by phpseclib
'1.3.6.1.5.5.7.1.12' => 'id-pe-logotype',
'1.2.840.113533.7.65.0' => 'entrustVersInfo',
'2.16.840.1.113733.1.6.9' => 'verisignPrivate',
// for Certificate Signing Requests
// see http://tools.ietf.org/html/rfc2985
'1.2.840.113549.1.9.2' => 'pkcs-9-at-unstructuredName', // PKCS #9 unstructured name
'1.2.840.113549.1.9.7' => 'pkcs-9-at-challengePassword', // Challenge password for certificate revocations
'1.2.840.113549.1.9.14' => 'pkcs-9-at-extensionRequest' // Certificate extension request
);
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @access public
*/
function File_X509()
{
$this->__construct();
}
/**
* Load X.509 certificate
*
* Returns an associative array describing the X.509 cert or a false if the cert failed to load
*
* @param string $cert
* @param int $mode
* @access public
* @return mixed
*/
function loadX509($cert, $mode = FILE_X509_FORMAT_AUTO_DETECT)
{
if (is_array($cert) && isset($cert['tbsCertificate'])) {
unset($this->currentCert);
unset($this->currentKeyIdentifier);
$this->dn = $cert['tbsCertificate']['subject'];
if (!isset($this->dn)) {
return false;
}
$this->currentCert = $cert;
$currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
$this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;
unset($this->signatureSubject);
return $cert;
}
$asn1 = new File_ASN1();
if ($mode != FILE_X509_FORMAT_DER) {
$newcert = $this->_extractBER($cert);
if ($mode == FILE_X509_FORMAT_PEM && $cert == $newcert) {
return false;
}
$cert = $newcert;
}
if ($cert === false) {
$this->currentCert = false;
return false;
}
$asn1->loadOIDs($this->oids);
$decoded = $asn1->decodeBER($cert);
if (!empty($decoded)) {
$x509 = $asn1->asn1map($decoded[0], $this->Certificate);
}
if (!isset($x509) || $x509 === false) {
$this->currentCert = false;
return false;
}
$this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
if ($this->_isSubArrayValid($x509, 'tbsCertificate/extensions')) {
$this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
}
$this->_mapInDNs($x509, 'tbsCertificate/issuer/rdnSequence', $asn1);
$this->_mapInDNs($x509, 'tbsCertificate/subject/rdnSequence', $asn1);
$key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'];
$key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key);
$this->currentCert = $x509;
$this->dn = $x509['tbsCertificate']['subject'];
$currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
$this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;
return $x509;
}
/**
* Save X.509 certificate
*
* @param array $cert
* @param int $format optional
* @access public
* @return string
*/
function saveX509($cert, $format = FILE_X509_FORMAT_PEM)
{
if (!is_array($cert) || !isset($cert['tbsCertificate'])) {
return false;
}
switch (true) {
// "case !$a: case !$b: break; default: whatever();" is the same thing as "if ($a && $b) whatever()"
case !($algorithm = $this->_subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')):
case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
break;
default:
switch ($algorithm) {
case 'rsaEncryption':
$cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));
/* "[For RSA keys] the parameters field MUST have ASN.1 type NULL for this algorithm identifier."
-- https://tools.ietf.org/html/rfc3279#section-2.3.1
given that and the fact that RSA keys appear ot be the only key type for which the parameters field can be blank,
it seems like perhaps the ASN.1 description ought not say the parameters field is OPTIONAL, but whatever.
*/
$cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = null;
// https://tools.ietf.org/html/rfc3279#section-2.2.1
$cert['signatureAlgorithm']['parameters'] = null;
$cert['tbsCertificate']['signature']['parameters'] = null;
}
}
$asn1 = new File_ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$type_utf8_string = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
$filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string;
$filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $type_utf8_string;
$filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $type_utf8_string;
$filters['tbsCertificate']['subject']['rdnSequence']['value'] = $type_utf8_string;
$filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $type_utf8_string;
$filters['signatureAlgorithm']['parameters'] = $type_utf8_string;
$filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
//$filters['policyQualifiers']['qualifier'] = $type_utf8_string;
$filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
$filters['directoryName']['rdnSequence']['value'] = $type_utf8_string;
/* in the case of policyQualifiers/qualifier, the type has to be FILE_ASN1_TYPE_IA5_STRING.
FILE_ASN1_TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random
characters.
*/
$filters['policyQualifiers']['qualifier']
= array('type' => FILE_ASN1_TYPE_IA5_STRING);
$asn1->loadFilters($filters);
$this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1);
$this->_mapOutDNs($cert, 'tbsCertificate/issuer/rdnSequence', $asn1);
$this->_mapOutDNs($cert, 'tbsCertificate/subject/rdnSequence', $asn1);
$cert = $asn1->encodeDER($cert, $this->Certificate);
switch ($format) {
case FILE_X509_FORMAT_DER:
return $cert;
// case FILE_X509_FORMAT_PEM:
default:
return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert), 64) . '-----END CERTIFICATE-----';
}
}
/**
* Map extension values from octet string to extension-specific internal
* format.
*
* @param array ref $root
* @param string $path
* @param object $asn1
* @access private
*/
function _mapInExtensions(&$root, $path, $asn1)
{
$extensions = &$this->_subArrayUnchecked($root, $path);
if ($extensions) {
for ($i = 0; $i < count($extensions); $i++) {
$id = $extensions[$i]['extnId'];
$value = &$extensions[$i]['extnValue'];
$value = base64_decode($value);
$decoded = $asn1->decodeBER($value);
/* [extnValue] contains the DER encoding of an ASN.1 value
corresponding to the extension type identified by extnID */
$map = $this->_getMapping($id);
if (!is_bool($map)) {
$mapped = $asn1->asn1map($decoded[0], $map, array('iPAddress' => array($this, '_decodeIP')));
$value = $mapped === false ? $decoded[0] : $mapped;
if ($id == 'id-ce-certificatePolicies') {
for ($j = 0; $j < count($value); $j++) {
if (!isset($value[$j]['policyQualifiers'])) {
continue;
}
for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
$subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
$map = $this->_getMapping($subid);
$subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
if ($map !== false) {
$decoded = $asn1->decodeBER($subvalue);
$mapped = $asn1->asn1map($decoded[0], $map);
$subvalue = $mapped === false ? $decoded[0] : $mapped;
}
}
}
}
} else {
$value = base64_encode($value);
}
}
}
}
/**
* Map extension values from extension-specific internal format to
* octet string.
*
* @param array ref $root
* @param string $path
* @param object $asn1
* @access private
*/
function _mapOutExtensions(&$root, $path, $asn1)
{
$extensions = &$this->_subArray($root, $path);
if (is_array($extensions)) {
$size = count($extensions);
for ($i = 0; $i < $size; $i++) {
if (is_object($extensions[$i]) && strtolower(get_class($extensions[$i])) == 'file_asn1_element') {
continue;
}
$id = $extensions[$i]['extnId'];
$value = &$extensions[$i]['extnValue'];
switch ($id) {
case 'id-ce-certificatePolicies':
for ($j = 0; $j < count($value); $j++) {
if (!isset($value[$j]['policyQualifiers'])) {
continue;
}
for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
$subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
$map = $this->_getMapping($subid);
$subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
if ($map !== false) {
// by default File_ASN1 will try to render qualifier as a FILE_ASN1_TYPE_IA5_STRING since it's
// actual type is FILE_ASN1_TYPE_ANY
$subvalue = new File_ASN1_Element($asn1->encodeDER($subvalue, $map));
}
}
}
break;
case 'id-ce-authorityKeyIdentifier': // use 00 as the serial number instead of an empty string
if (isset($value['authorityCertSerialNumber'])) {
if ($value['authorityCertSerialNumber']->toBytes() == '') {
$temp = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0";
$value['authorityCertSerialNumber'] = new File_ASN1_Element($temp);
}
}
}
/* [extnValue] contains the DER encoding of an ASN.1 value
corresponding to the extension type identified by extnID */
$map = $this->_getMapping($id);
if (is_bool($map)) {
if (!$map) {
user_error($id . ' is not a currently supported extension');
unset($extensions[$i]);
}
} else {
$temp = $asn1->encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP')));
$value = base64_encode($temp);
}
}
}
}
/**
* Map attribute values from ANY type to attribute-specific internal
* format.
*
* @param array ref $root
* @param string $path
* @param object $asn1
* @access private
*/
function _mapInAttributes(&$root, $path, $asn1)
{
$attributes = &$this->_subArray($root, $path);
if (is_array($attributes)) {
for ($i = 0; $i < count($attributes); $i++) {
$id = $attributes[$i]['type'];
/* $value contains the DER encoding of an ASN.1 value
corresponding to the attribute type identified by type */
$map = $this->_getMapping($id);
if (is_array($attributes[$i]['value'])) {
$values = &$attributes[$i]['value'];
for ($j = 0; $j < count($values); $j++) {
$value = $asn1->encodeDER($values[$j], $this->AttributeValue);
$decoded = $asn1->decodeBER($value);
if (!is_bool($map)) {
$mapped = $asn1->asn1map($decoded[0], $map);
if ($mapped !== false) {
$values[$j] = $mapped;
}
if ($id == 'pkcs-9-at-extensionRequest' && $this->_isSubArrayValid($values, $j)) {
$this->_mapInExtensions($values, $j, $asn1);
}
} elseif ($map) {
$values[$j] = base64_encode($value);
}
}
}
}
}
}
/**
* Map attribute values from attribute-specific internal format to
* ANY type.
*
* @param array ref $root
* @param string $path
* @param object $asn1
* @access private
*/
function _mapOutAttributes(&$root, $path, $asn1)
{
$attributes = &$this->_subArray($root, $path);
if (is_array($attributes)) {
$size = count($attributes);
for ($i = 0; $i < $size; $i++) {
/* [value] contains the DER encoding of an ASN.1 value
corresponding to the attribute type identified by type */
$id = $attributes[$i]['type'];
$map = $this->_getMapping($id);
if ($map === false) {
user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
unset($attributes[$i]);
} elseif (is_array($attributes[$i]['value'])) {
$values = &$attributes[$i]['value'];
for ($j = 0; $j < count($values); $j++) {
switch ($id) {
case 'pkcs-9-at-extensionRequest':
$this->_mapOutExtensions($values, $j, $asn1);
break;
}
if (!is_bool($map)) {
$temp = $asn1->encodeDER($values[$j], $map);
$decoded = $asn1->decodeBER($temp);
$values[$j] = $asn1->asn1map($decoded[0], $this->AttributeValue);
}
}
}
}
}
}
/**
* Map DN values from ANY type to DN-specific internal
* format.
*
* @param array ref $root
* @param string $path
* @param object $asn1
* @access private
*/
function _mapInDNs(&$root, $path, $asn1)
{
$dns = &$this->_subArray($root, $path);
if (is_array($dns)) {
for ($i = 0; $i < count($dns); $i++) {
for ($j = 0; $j < count($dns[$i]); $j++) {
$type = $dns[$i][$j]['type'];
$value = &$dns[$i][$j]['value'];
if (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') {
$map = $this->_getMapping($type);
if (!is_bool($map)) {
$decoded = $asn1->decodeBER($value);
$value = $asn1->asn1map($decoded[0], $map);
}
}
}
}
}
}
/**
* Map DN values from DN-specific internal format to
* ANY type.
*
* @param array ref $root
* @param string $path
* @param object $asn1
* @access private
*/
function _mapOutDNs(&$root, $path, $asn1)
{
$dns = &$this->_subArray($root, $path);
if (is_array($dns)) {
$size = count($dns);
for ($i = 0; $i < $size; $i++) {
for ($j = 0; $j < count($dns[$i]); $j++) {
$type = $dns[$i][$j]['type'];
$value = &$dns[$i][$j]['value'];
if (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') {
continue;
}
$map = $this->_getMapping($type);
if (!is_bool($map)) {
$value = new File_ASN1_Element($asn1->encodeDER($value, $map));
}
}
}
}
}
/**
* Associate an extension ID to an extension mapping
*
* @param string $extnId
* @access private
* @return mixed
*/
function _getMapping($extnId)
{
if (!is_string($extnId)) { // eg. if it's a File_ASN1_Element object
return true;
}
switch ($extnId) {
case 'id-ce-keyUsage':
return $this->KeyUsage;
case 'id-ce-basicConstraints':
return $this->BasicConstraints;
case 'id-ce-subjectKeyIdentifier':
return $this->KeyIdentifier;
case 'id-ce-cRLDistributionPoints':
return $this->CRLDistributionPoints;
case 'id-ce-authorityKeyIdentifier':
return $this->AuthorityKeyIdentifier;
case 'id-ce-certificatePolicies':
return $this->CertificatePolicies;
case 'id-ce-extKeyUsage':
return $this->ExtKeyUsageSyntax;
case 'id-pe-authorityInfoAccess':
return $this->AuthorityInfoAccessSyntax;
case 'id-ce-subjectAltName':
return $this->SubjectAltName;
case 'id-ce-subjectDirectoryAttributes':
return $this->SubjectDirectoryAttributes;
case 'id-ce-privateKeyUsagePeriod':
return $this->PrivateKeyUsagePeriod;
case 'id-ce-issuerAltName':
return $this->IssuerAltName;
case 'id-ce-policyMappings':
return $this->PolicyMappings;
case 'id-ce-nameConstraints':
return $this->NameConstraints;
case 'netscape-cert-type':
return $this->netscape_cert_type;
case 'netscape-comment':
return $this->netscape_comment;
case 'netscape-ca-policy-url':
return $this->netscape_ca_policy_url;
// since id-qt-cps isn't a constructed type it will have already been decoded as a string by the time it gets
// back around to asn1map() and we don't want it decoded again.
//case 'id-qt-cps':
// return $this->CPSuri;
case 'id-qt-unotice':
return $this->UserNotice;
// the following OIDs are unsupported but we don't want them to give notices when calling saveX509().
case 'id-pe-logotype': // http://www.ietf.org/rfc/rfc3709.txt
case 'entrustVersInfo':
// http://support.microsoft.com/kb/287547
case '1.3.6.1.4.1.311.20.2': // szOID_ENROLL_CERTTYPE_EXTENSION
case '1.3.6.1.4.1.311.21.1': // szOID_CERTSRV_CA_VERSION
// "SET Secure Electronic Transaction Specification"
// http://www.maithean.com/docs/set_bk3.pdf
case '2.23.42.7.0': // id-set-hashedRootKey
// "Certificate Transparency"
// https://tools.ietf.org/html/rfc6962
case '1.3.6.1.4.1.11129.2.4.2':
// "Qualified Certificate statements"
// https://tools.ietf.org/html/rfc3739#section-3.2.6
case '1.3.6.1.5.5.7.1.3':
return true;
// CSR attributes
case 'pkcs-9-at-unstructuredName':
return $this->PKCS9String;
case 'pkcs-9-at-challengePassword':
return $this->DirectoryString;
case 'pkcs-9-at-extensionRequest':
return $this->Extensions;
// CRL extensions.
case 'id-ce-cRLNumber':
return $this->CRLNumber;
case 'id-ce-deltaCRLIndicator':
return $this->CRLNumber;
case 'id-ce-issuingDistributionPoint':
return $this->IssuingDistributionPoint;
case 'id-ce-freshestCRL':
return $this->CRLDistributionPoints;
case 'id-ce-cRLReasons':
return $this->CRLReason;
case 'id-ce-invalidityDate':
return $this->InvalidityDate;
case 'id-ce-certificateIssuer':
return $this->CertificateIssuer;
case 'id-ce-holdInstructionCode':
return $this->HoldInstructionCode;
case 'id-at-postalAddress':
return $this->PostalAddress;
}
return false;
}
/**
* Load an X.509 certificate as a certificate authority
*
* @param string $cert
* @access public
* @return bool
*/
function loadCA($cert)
{
$olddn = $this->dn;
$oldcert = $this->currentCert;
$oldsigsubj = $this->signatureSubject;
$oldkeyid = $this->currentKeyIdentifier;
$cert = $this->loadX509($cert);
if (!$cert) {
$this->dn = $olddn;
$this->currentCert = $oldcert;
$this->signatureSubject = $oldsigsubj;
$this->currentKeyIdentifier = $oldkeyid;
return false;
}
/* From RFC5280 "PKIX Certificate and CRL Profile":
If the keyUsage extension is present, then the subject public key
MUST NOT be used to verify signatures on certificates or CRLs unless
the corresponding keyCertSign or cRLSign bit is set. */
//$keyUsage = $this->getExtension('id-ce-keyUsage');
//if ($keyUsage && !in_array('keyCertSign', $keyUsage)) {
// return false;
//}
/* From RFC5280 "PKIX Certificate and CRL Profile":
The cA boolean indicates whether the certified public key may be used
to verify certificate signatures. If the cA boolean is not asserted,
then the keyCertSign bit in the key usage extension MUST NOT be
asserted. If the basic constraints extension is not present in a
version 3 certificate, or the extension is present but the cA boolean
is not asserted, then the certified public key MUST NOT be used to
verify certificate signatures. */
//$basicConstraints = $this->getExtension('id-ce-basicConstraints');
//if (!$basicConstraints || !$basicConstraints['cA']) {
// return false;
//}
$this->CAs[] = $cert;
$this->dn = $olddn;
$this->currentCert = $oldcert;
$this->signatureSubject = $oldsigsubj;
return true;
}
/**
* Validate an X.509 certificate against a URL
*
* From RFC2818 "HTTP over TLS":
*
* Matching is performed using the matching rules specified by
* [RFC2459]. If more than one identity of a given type is present in
* the certificate (e.g., more than one dNSName name, a match in any one
* of the set is considered acceptable.) Names may contain the wildcard
* character * which is considered to match any single domain name
* component or component fragment. E.g., *.a.com matches foo.a.com but
* not bar.foo.a.com. f*.com matches foo.com but not bar.com.
*
* @param string $url
* @access public
* @return bool
*/
function validateURL($url)
{
if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
return false;
}
$components = parse_url($url);
if (!isset($components['host'])) {
return false;
}
if ($names = $this->getExtension('id-ce-subjectAltName')) {
foreach ($names as $name) {
foreach ($name as $key => $value) {
$value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
switch ($key) {
case 'dNSName':
/* From RFC2818 "HTTP over TLS":
If a subjectAltName extension of type dNSName is present, that MUST
be used as the identity. Otherwise, the (most specific) Common Name
field in the Subject field of the certificate MUST be used. Although
the use of the Common Name is existing practice, it is deprecated and
Certification Authorities are encouraged to use the dNSName instead. */
if (preg_match('#^' . $value . '$#', $components['host'])) {
return true;
}
break;
case 'iPAddress':
/* From RFC2818 "HTTP over TLS":
In some cases, the URI is specified as an IP address rather than a
hostname. In this case, the iPAddress subjectAltName must be present
in the certificate and must exactly match the IP in the URI. */
if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
return true;
}
}
}
}
return false;
}
if ($value = $this->getDNProp('id-at-commonName')) {
$value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value[0]);
return preg_match('#^' . $value . '$#', $components['host']);
}
return false;
}
/**
* Validate a date
*
* If $date isn't defined it is assumed to be the current date.
*
* @param \DateTime|int|string $date optional
* @access public
*/
function validateDate($date = null)
{
if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
return false;
}
if (!isset($date)) {
$date = class_exists('DateTime') ?
new DateTime(null, new DateTimeZone(@date_default_timezone_get())) :
time();
}
$notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
$notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime'];
$notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
$notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
switch (true) {
case is_string($date) && class_exists('DateTime'):
$date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
case is_object($date) && strtolower(get_class($date)) == 'datetime':
$notBefore = new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get()));
$notAfter = new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get()));
break;
case is_string($date):
$date = @strtotime($date);
default:
$notBefore = @strtotime($notBefore);
$notAfter = @strtotime($notAfter);
}
switch (true) {
case $date < $notBefore:
case $date > $notAfter:
return false;
}
return true;
}
/**
* Fetches a URL
*
* @param string $url
* @access private
* @return bool|string
*/
function _fetchURL($url)
{
if ($this->disable_url_fetch) {
return false;
}
$parts = parse_url($url);
$data = '';
switch ($parts['scheme']) {
case 'http':
$fsock = @fsockopen($parts['host'], isset($parts['port']) ? $parts['port'] : 80);
if (!$fsock) {
return false;
}
fputs($fsock, "GET $parts[path] HTTP/1.0\r\n");
fputs($fsock, "Host: $parts[host]\r\n\r\n");
$line = fgets($fsock, 1024);
if (strlen($line) < 3) {
return false;
}
preg_match('#HTTP/1.\d (\d{3})#', $line, $temp);
if ($temp[1] != '200') {
return false;
}
// skip the rest of the headers in the http response
while (!feof($fsock) && fgets($fsock, 1024) != "\r\n") {
}
while (!feof($fsock)) {
$data.= fread($fsock, 1024);
}
break;
//case 'ftp':
//case 'ldap':
//default:
}
return $data;
}
/**
* Validates an intermediate cert as identified via authority info access extension
*
* See https://tools.ietf.org/html/rfc4325 for more info
*
* @param bool $caonly
* @param int $count
* @access private
* @return bool
*/
function _testForIntermediate($caonly, $count)
{
$opts = $this->getExtension('id-pe-authorityInfoAccess');
if (!is_array($opts)) {
return false;
}
foreach ($opts as $opt) {
if ($opt['accessMethod'] == 'id-ad-caIssuers') {
// accessLocation is a GeneralName. GeneralName fields support stuff like email addresses, IP addresses, LDAP,
// etc, but we're only supporting URI's. URI's and LDAP are the only thing https://tools.ietf.org/html/rfc4325
// discusses
if (isset($opt['accessLocation']['uniformResourceIdentifier'])) {
$url = $opt['accessLocation']['uniformResourceIdentifier'];
break;
}
}
}
if (!isset($url)) {
return false;
}
$cert = $this->_fetchURL($url);
if (!is_string($cert)) {
return false;
}
$parent = new static();
$parent->CAs = $this->CAs;
/*
"Conforming applications that support HTTP or FTP for accessing
certificates MUST be able to accept .cer files and SHOULD be able
to accept .p7c files." -- https://tools.ietf.org/html/rfc4325
A .p7c file is 'a "certs-only" CMS message as specified in RFC 2797"
These are currently unsupported
*/
if (!is_array($parent->loadX509($cert))) {
return false;
}
if (!$parent->_validateSignatureCountable($caonly, ++$count)) {
return false;
}
$this->CAs[] = $parent->currentCert;
//$this->loadCA($cert);
return true;
}
/**
* Validate a signature
*
* Works on X.509 certs, CSR's and CRL's.
* Returns true if the signature is verified, false if it is not correct or null on error
*
* By default returns false for self-signed certs. Call validateSignature(false) to make this support
* self-signed.
*
* The behavior of this function is inspired by {@link http://php.net/openssl-verify openssl_verify}.
*
* @param bool $caonly optional
* @access public
* @return mixed
*/
function validateSignature($caonly = true)
{
return $this->_validateSignatureCountable($caonly, 0);
}
/**
* Validate a signature
*
* Performs said validation whilst keeping track of how many times validation method is called
*
* @param bool $caonly
* @param int $count
* @access private
* @return mixed
*/
function _validateSignatureCountable($caonly, $count)
{
if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
return null;
}
if ($count == $this->recur_limit) {
return false;
}
/* TODO:
"emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")."
-- http://tools.ietf.org/html/rfc5280#section-4.1.2.6
implement pathLenConstraint in the id-ce-basicConstraints extension */
switch (true) {
case isset($this->currentCert['tbsCertificate']):
// self-signed cert
switch (true) {
case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']:
case defined('FILE_X509_IGNORE_TYPE') && $this->getIssuerDN(FILE_X509_DN_STRING) === $this->getDN(FILE_X509_DN_STRING):
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
switch (true) {
case !is_array($authorityKey):
case !$subjectKeyID:
case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
$signingCert = $this->currentCert; // working cert
}
}
if (!empty($this->CAs)) {
for ($i = 0; $i < count($this->CAs); $i++) {
// even if the cert is a self-signed one we still want to see if it's a CA;
// if not, we'll conditionally return an error
$ca = $this->CAs[$i];
switch (true) {
case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']:
case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(FILE_X509_DN_STRING, $this->currentCert['tbsCertificate']['issuer']) === $this->getDN(FILE_X509_DN_STRING, $ca['tbsCertificate']['subject']):
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
case !$subjectKeyID:
case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
break 2; // serial mismatch - check other ca
}
$signingCert = $ca; // working cert
break 3;
}
}
}
if (count($this->CAs) == $i && $caonly) {
return $this->_testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
}
} elseif (!isset($signingCert) || $caonly) {
return $this->_testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
}
return $this->_validateSignature(
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
case isset($this->currentCert['certificationRequestInfo']):
return $this->_validateSignature(
$this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'],
$this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
case isset($this->currentCert['publicKeyAndChallenge']):
return $this->_validateSignature(
$this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'],
$this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
case isset($this->currentCert['tbsCertList']):
if (!empty($this->CAs)) {
for ($i = 0; $i < count($this->CAs); $i++) {
$ca = $this->CAs[$i];
switch (true) {
case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']:
case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(FILE_X509_DN_STRING, $this->currentCert['tbsCertList']['issuer']) === $this->getDN(FILE_X509_DN_STRING, $ca['tbsCertificate']['subject']):
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
case !$subjectKeyID:
case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
break 2; // serial mismatch - check other ca
}
$signingCert = $ca; // working cert
break 3;
}
}
}
}
if (!isset($signingCert)) {
return false;
}
return $this->_validateSignature(
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
default:
return false;
}
}
/**
* Validates a signature
*
* Returns true if the signature is verified, false if it is not correct or null on error
*
* @param string $publicKeyAlgorithm
* @param string $publicKey
* @param string $signatureAlgorithm
* @param string $signature
* @param string $signatureSubject
* @access private
* @return int
*/
function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
{
switch ($publicKeyAlgorithm) {
case 'rsaEncryption':
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$rsa = new Crypt_RSA();
$rsa->loadKey($publicKey);
switch ($signatureAlgorithm) {
case 'md2WithRSAEncryption':
case 'md5WithRSAEncryption':
case 'sha1WithRSAEncryption':
case 'sha224WithRSAEncryption':
case 'sha256WithRSAEncryption':
case 'sha384WithRSAEncryption':
case 'sha512WithRSAEncryption':
$rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
if (!@$rsa->verify($signatureSubject, $signature)) {
return false;
}
break;
default:
return null;
}
break;
default:
return null;
}
return true;
}
/**
* Sets the recursion limit
*
* When validating a signature it may be necessary to download intermediate certs from URI's.
* An intermediate cert that linked to itself would result in an infinite loop so to prevent
* that we set a recursion limit. A negative number means that there is no recursion limit.
*
* @param int $count
* @access public
*/
function setRecurLimit($count)
{
$this->recur_limit = $count;
}
/**
* Prevents URIs from being automatically retrieved
*
* @access public
*/
function disableURLFetch()
{
$this->disable_url_fetch = true;
}
/**
* Allows URIs to be automatically retrieved
*
* @access public
*/
function enableURLFetch()
{
$this->disable_url_fetch = false;
}
/**
* Reformat public keys
*
* Reformats a public key to a format supported by phpseclib (if applicable)
*
* @param string $algorithm
* @param string $key
* @access private
* @return string
*/
function _reformatKey($algorithm, $key)
{
switch ($algorithm) {
case 'rsaEncryption':
return
"-----BEGIN RSA PUBLIC KEY-----\r\n" .
// subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits
// in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox
// uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do.
chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) .
'-----END RSA PUBLIC KEY-----';
default:
return $key;
}
}
/**
* Decodes an IP address
*
* Takes in a base64 encoded "blob" and returns a human readable IP address
*
* @param string $ip
* @access private
* @return string
*/
function _decodeIP($ip)
{
$ip = base64_decode($ip);
list(, $ip) = unpack('N', $ip);
return long2ip($ip);
}
/**
* Encodes an IP address
*
* Takes a human readable IP address into a base64-encoded "blob"
*
* @param string $ip
* @access private
* @return string
*/
function _encodeIP($ip)
{
return base64_encode(pack('N', ip2long($ip)));
}
/**
* "Normalizes" a Distinguished Name property
*
* @param string $propName
* @access private
* @return mixed
*/
function _translateDNProp($propName)
{
switch (strtolower($propName)) {
case 'id-at-countryname':
case 'countryname':
case 'c':
return 'id-at-countryName';
case 'id-at-organizationname':
case 'organizationname':
case 'o':
return 'id-at-organizationName';
case 'id-at-dnqualifier':
case 'dnqualifier':
return 'id-at-dnQualifier';
case 'id-at-commonname':
case 'commonname':
case 'cn':
return 'id-at-commonName';
case 'id-at-stateorprovincename':
case 'stateorprovincename':
case 'state':
case 'province':
case 'provincename':
case 'st':
return 'id-at-stateOrProvinceName';
case 'id-at-localityname':
case 'localityname':
case 'l':
return 'id-at-localityName';
case 'id-emailaddress':
case 'emailaddress':
return 'pkcs-9-at-emailAddress';
case 'id-at-serialnumber':
case 'serialnumber':
return 'id-at-serialNumber';
case 'id-at-postalcode':
case 'postalcode':
return 'id-at-postalCode';
case 'id-at-streetaddress':
case 'streetaddress':
return 'id-at-streetAddress';
case 'id-at-name':
case 'name':
return 'id-at-name';
case 'id-at-givenname':
case 'givenname':
return 'id-at-givenName';
case 'id-at-surname':
case 'surname':
case 'sn':
return 'id-at-surname';
case 'id-at-initials':
case 'initials':
return 'id-at-initials';
case 'id-at-generationqualifier':
case 'generationqualifier':
return 'id-at-generationQualifier';
case 'id-at-organizationalunitname':
case 'organizationalunitname':
case 'ou':
return 'id-at-organizationalUnitName';
case 'id-at-pseudonym':
case 'pseudonym':
return 'id-at-pseudonym';
case 'id-at-title':
case 'title':
return 'id-at-title';
case 'id-at-description':
case 'description':
return 'id-at-description';
case 'id-at-role':
case 'role':
return 'id-at-role';
case 'id-at-uniqueidentifier':
case 'uniqueidentifier':
case 'x500uniqueidentifier':
return 'id-at-uniqueIdentifier';
case 'postaladdress':
case 'id-at-postaladdress':
return 'id-at-postalAddress';
default:
return false;
}
}
/**
* Set a Distinguished Name property
*
* @param string $propName
* @param mixed $propValue
* @param string $type optional
* @access public
* @return bool
*/
function setDNProp($propName, $propValue, $type = 'utf8String')
{
if (empty($this->dn)) {
$this->dn = array('rdnSequence' => array());
}
if (($propName = $this->_translateDNProp($propName)) === false) {
return false;
}
foreach ((array) $propValue as $v) {
if (!is_array($v) && isset($type)) {
$v = array($type => $v);
}
$this->dn['rdnSequence'][] = array(
array(
'type' => $propName,
'value'=> $v
)
);
}
return true;
}
/**
* Remove Distinguished Name properties
*
* @param string $propName
* @access public
*/
function removeDNProp($propName)
{
if (empty($this->dn)) {
return;
}
if (($propName = $this->_translateDNProp($propName)) === false) {
return;
}
$dn = &$this->dn['rdnSequence'];
$size = count($dn);
for ($i = 0; $i < $size; $i++) {
if ($dn[$i][0]['type'] == $propName) {
unset($dn[$i]);
}
}
$dn = array_values($dn);
// fix for https://bugs.php.net/75433 affecting PHP 7.2
if (!isset($dn[0])) {
$dn = array_splice($dn, 0, 0);
}
}
/**
* Get Distinguished Name properties
*
* @param string $propName
* @param array $dn optional
* @param bool $withType optional
* @return mixed
* @access public
*/
function getDNProp($propName, $dn = null, $withType = false)
{
if (!isset($dn)) {
$dn = $this->dn;
}
if (empty($dn)) {
return false;
}
if (($propName = $this->_translateDNProp($propName)) === false) {
return false;
}
$asn1 = new File_ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);
$dn = $dn['rdnSequence'];
$result = array();
for ($i = 0; $i < count($dn); $i++) {
if ($dn[$i][0]['type'] == $propName) {
$v = $dn[$i][0]['value'];
if (!$withType) {
if (is_array($v)) {
foreach ($v as $type => $s) {
$type = array_search($type, $asn1->ANYmap, true);
if ($type !== false && isset($asn1->stringTypeSize[$type])) {
$s = $asn1->convert($s, $type);
if ($s !== false) {
$v = $s;
break;
}
}
}
if (is_array($v)) {
$v = array_pop($v); // Always strip data type.
}
} elseif (is_object($v) && strtolower(get_class($v)) == 'file_asn1_element') {
$map = $this->_getMapping($propName);
if (!is_bool($map)) {
$decoded = $asn1->decodeBER($v);
$v = $asn1->asn1map($decoded[0], $map);
}
}
}
$result[] = $v;
}
}
return $result;
}
/**
* Set a Distinguished Name
*
* @param mixed $dn
* @param bool $merge optional
* @param string $type optional
* @access public
* @return bool
*/
function setDN($dn, $merge = false, $type = 'utf8String')
{
if (!$merge) {
$this->dn = null;
}
if (is_array($dn)) {
if (isset($dn['rdnSequence'])) {
$this->dn = $dn; // No merge here.
return true;
}
// handles stuff generated by openssl_x509_parse()
foreach ($dn as $prop => $value) {
if (!$this->setDNProp($prop, $value, $type)) {
return false;
}
}
return true;
}
// handles everything else
$results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=|postalAddress=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
for ($i = 1; $i < count($results); $i+=2) {
$prop = trim($results[$i], ', =/');
$value = $results[$i + 1];
if (!$this->setDNProp($prop, $value, $type)) {
return false;
}
}
return true;
}
/**
* Get the Distinguished Name for a certificates subject
*
* @param mixed $format optional
* @param array $dn optional
* @access public
* @return bool
*/
function getDN($format = FILE_X509_DN_ARRAY, $dn = null)
{
if (!isset($dn)) {
$dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn;
}
switch ((int) $format) {
case FILE_X509_DN_ARRAY:
return $dn;
case FILE_X509_DN_ASN1:
$asn1 = new File_ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['rdnSequence']['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);
return $asn1->encodeDER($dn, $this->Name);
case FILE_X509_DN_CANON:
// No SEQUENCE around RDNs and all string values normalized as
// trimmed lowercase UTF-8 with all spacing as one blank.
// constructed RDNs will not be canonicalized
$asn1 = new File_ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$result = '';
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);
foreach ($dn['rdnSequence'] as $rdn) {
foreach ($rdn as $i => $attr) {
$attr = &$rdn[$i];
if (is_array($attr['value'])) {
foreach ($attr['value'] as $type => $v) {
$type = array_search($type, $asn1->ANYmap, true);
if ($type !== false && isset($asn1->stringTypeSize[$type])) {
$v = $asn1->convert($v, $type);
if ($v !== false) {
$v = preg_replace('/\s+/', ' ', $v);
$attr['value'] = strtolower(trim($v));
break;
}
}
}
}
}
$result .= $asn1->encodeDER($rdn, $this->RelativeDistinguishedName);
}
return $result;
case FILE_X509_DN_HASH:
$dn = $this->getDN(FILE_X509_DN_CANON, $dn);
if (!class_exists('Crypt_Hash')) {
include_once 'Crypt/Hash.php';
}
$hash = new Crypt_Hash('sha1');
$hash = $hash->hash($dn);
extract(unpack('Vhash', $hash));
return strtolower(bin2hex(pack('N', $hash)));
}
// Default is to return a string.
$start = true;
$output = '';
$result = array();
$asn1 = new File_ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['rdnSequence']['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);
foreach ($dn['rdnSequence'] as $field) {
$prop = $field[0]['type'];
$value = $field[0]['value'];
$delim = ', ';
switch ($prop) {
case 'id-at-countryName':
$desc = 'C';
break;
case 'id-at-stateOrProvinceName':
$desc = 'ST';
break;
case 'id-at-organizationName':
$desc = 'O';
break;
case 'id-at-organizationalUnitName':
$desc = 'OU';
break;
case 'id-at-commonName':
$desc = 'CN';
break;
case 'id-at-localityName':
$desc = 'L';
break;
case 'id-at-surname':
$desc = 'SN';
break;
case 'id-at-uniqueIdentifier':
$delim = '/';
$desc = 'x500UniqueIdentifier';
break;
case 'id-at-postalAddress':
$delim = '/';
$desc = 'postalAddress';
break;
default:
$delim = '/';
$desc = preg_replace('#.+-([^-]+)$#', '$1', $prop);
}
if (!$start) {
$output.= $delim;
}
if (is_array($value)) {
foreach ($value as $type => $v) {
$type = array_search($type, $asn1->ANYmap, true);
if ($type !== false && isset($asn1->stringTypeSize[$type])) {
$v = $asn1->convert($v, $type);
if ($v !== false) {
$value = $v;
break;
}
}
}
if (is_array($value)) {
$value = array_pop($value); // Always strip data type.
}
} elseif (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') {
// @codingStandardsIgnoreStart
$callback = version_compare(PHP_VERSION, '5.3.0') >= 0 ?
function ($x) { return "\x" . bin2hex($x[0]); } :
create_function('$x', 'return "\x" . bin2hex($x[0]);');
// @codingStandardsIgnoreEnd
$value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element));
}
$output.= $desc . '=' . $value;
$result[$desc] = isset($result[$desc]) ?
array_merge((array) $result[$desc], array($value)) :
$value;
$start = false;
}
return $format == FILE_X509_DN_OPENSSL ? $result : $output;
}
/**
* Get the Distinguished Name for a certificate/crl issuer
*
* @param int $format optional
* @access public
* @return mixed
*/
function getIssuerDN($format = FILE_X509_DN_ARRAY)
{
switch (true) {
case !isset($this->currentCert) || !is_array($this->currentCert):
break;
case isset($this->currentCert['tbsCertificate']):
return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']);
case isset($this->currentCert['tbsCertList']):
return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']);
}
return false;
}
/**
* Get the Distinguished Name for a certificate/csr subject
* Alias of getDN()
*
* @param int $format optional
* @access public
* @return mixed
*/
function getSubjectDN($format = FILE_X509_DN_ARRAY)
{
switch (true) {
case !empty($this->dn):
return $this->getDN($format);
case !isset($this->currentCert) || !is_array($this->currentCert):
break;
case isset($this->currentCert['tbsCertificate']):
return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']);
case isset($this->currentCert['certificationRequestInfo']):
return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']);
}
return false;
}
/**
* Get an individual Distinguished Name property for a certificate/crl issuer
*
* @param string $propName
* @param bool $withType optional
* @access public
* @return mixed
*/
function getIssuerDNProp($propName, $withType = false)
{
switch (true) {
case !isset($this->currentCert) || !is_array($this->currentCert):
break;
case isset($this->currentCert['tbsCertificate']):
return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType);
case isset($this->currentCert['tbsCertList']):
return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType);
}
return false;
}
/**
* Get an individual Distinguished Name property for a certificate/csr subject
*
* @param string $propName
* @param bool $withType optional
* @access public
* @return mixed
*/
function getSubjectDNProp($propName, $withType = false)
{
switch (true) {
case !empty($this->dn):
return $this->getDNProp($propName, null, $withType);
case !isset($this->currentCert) || !is_array($this->currentCert):
break;
case isset($this->currentCert['tbsCertificate']):
return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType);
case isset($this->currentCert['certificationRequestInfo']):
return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType);
}
return false;
}
/**
* Get the certificate chain for the current cert
*
* @access public
* @return mixed
*/
function getChain()
{
$chain = array($this->currentCert);
if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
return false;
}
if (empty($this->CAs)) {
return $chain;
}
while (true) {
$currentCert = $chain[count($chain) - 1];
for ($i = 0; $i < count($this->CAs); $i++) {
$ca = $this->CAs[$i];
if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert);
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
if ($currentCert === $ca) {
break 3;
}
$chain[] = $ca;
break 2;
}
}
}
if ($i == count($this->CAs)) {
break;
}
}
foreach ($chain as $key => $value) {
$chain[$key] = new File_X509();
$chain[$key]->loadX509($value);
}
return $chain;
}
/**
* Set public key
*
* Key needs to be a Crypt_RSA object
*
* @param object $key
* @access public
* @return bool
*/
function setPublicKey($key)
{
$key->setPublicKey();
$this->publicKey = $key;
}
/**
* Set private key
*
* Key needs to be a Crypt_RSA object
*
* @param object $key
* @access public
*/
function setPrivateKey($key)
{
$this->privateKey = $key;
}
/**
* Set challenge
*
* Used for SPKAC CSR's
*
* @param string $challenge
* @access public
*/
function setChallenge($challenge)
{
$this->challenge = $challenge;
}
/**
* Gets the public key
*
* Returns a Crypt_RSA object or a false.
*
* @access public
* @return mixed
*/
function getPublicKey()
{
if (isset($this->publicKey)) {
return $this->publicKey;
}
if (isset($this->currentCert) && is_array($this->currentCert)) {
foreach (array('tbsCertificate/subjectPublicKeyInfo', 'certificationRequestInfo/subjectPKInfo') as $path) {
$keyinfo = $this->_subArray($this->currentCert, $path);
if (!empty($keyinfo)) {
break;
}
}
}
if (empty($keyinfo)) {
return false;
}
$key = $keyinfo['subjectPublicKey'];
switch ($keyinfo['algorithm']['algorithm']) {
case 'rsaEncryption':
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$publicKey = new Crypt_RSA();
$publicKey->loadKey($key);
$publicKey->setPublicKey();
break;
default:
return false;
}
return $publicKey;
}
/**
* Load a Certificate Signing Request
*
* @param string $csr
* @access public
* @return mixed
*/
function loadCSR($csr, $mode = FILE_X509_FORMAT_AUTO_DETECT)
{
if (is_array($csr) && isset($csr['certificationRequestInfo'])) {
unset($this->currentCert);
unset($this->currentKeyIdentifier);
unset($this->signatureSubject);
$this->dn = $csr['certificationRequestInfo']['subject'];
if (!isset($this->dn)) {
return false;
}
$this->currentCert = $csr;
return $csr;
}
// see http://tools.ietf.org/html/rfc2986
$asn1 = new File_ASN1();
if ($mode != FILE_X509_FORMAT_DER) {
$newcsr = $this->_extractBER($csr);
if ($mode == FILE_X509_FORMAT_PEM && $csr == $newcsr) {
return false;
}
$csr = $newcsr;
}
$orig = $csr;
if ($csr === false) {
$this->currentCert = false;
return false;
}
$asn1->loadOIDs($this->oids);
$decoded = $asn1->decodeBER($csr);
if (empty($decoded)) {
$this->currentCert = false;
return false;
}
$csr = $asn1->asn1map($decoded[0], $this->CertificationRequest);
if (!isset($csr) || $csr === false) {
$this->currentCert = false;
return false;
}
$this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
$this->_mapInDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
$this->dn = $csr['certificationRequestInfo']['subject'];
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
$algorithm = &$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'];
$key = &$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'];
$key = $this->_reformatKey($algorithm, $key);
switch ($algorithm) {
case 'rsaEncryption':
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$this->publicKey = new Crypt_RSA();
$this->publicKey->loadKey($key);
$this->publicKey->setPublicKey();
break;
default:
$this->publicKey = null;
}
$this->currentKeyIdentifier = null;
$this->currentCert = $csr;
return $csr;
}
/**
* Save CSR request
*
* @param array $csr
* @param int $format optional
* @access public
* @return string
*/
function saveCSR($csr, $format = FILE_X509_FORMAT_PEM)
{
if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) {
return false;
}
switch (true) {
case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')):
case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
break;
default:
switch ($algorithm) {
case 'rsaEncryption':
$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['parameters'] = null;
$csr['signatureAlgorithm']['parameters'] = null;
$csr['certificationRequestInfo']['signature']['parameters'] = null;
}
}
$asn1 = new File_ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['certificationRequestInfo']['subject']['rdnSequence']['value']
= array('type' => FILE_ASN1_TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$this->_mapOutDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
$this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
$csr = $asn1->encodeDER($csr, $this->CertificationRequest);
switch ($format) {
case FILE_X509_FORMAT_DER:
return $csr;
// case FILE_X509_FORMAT_PEM:
default:
return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----';
}
}
/**
* Load a SPKAC CSR
*
* SPKAC's are produced by the HTML5 keygen element:
*
* https://developer.mozilla.org/en-US/docs/HTML/Element/keygen
*
* @param string $csr
* @access public
* @return mixed
*/
function loadSPKAC($spkac)
{
if (is_array($spkac) && isset($spkac['publicKeyAndChallenge'])) {
unset($this->currentCert);
unset($this->currentKeyIdentifier);
unset($this->signatureSubject);
$this->currentCert = $spkac;
return $spkac;
}
// see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge
$asn1 = new File_ASN1();
// OpenSSL produces SPKAC's that are preceded by the string SPKAC=
$temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac);
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
if ($temp != false) {
$spkac = $temp;
}
$orig = $spkac;
if ($spkac === false) {
$this->currentCert = false;
return false;
}
$asn1->loadOIDs($this->oids);
$decoded = $asn1->decodeBER($spkac);
if (empty($decoded)) {
$this->currentCert = false;
return false;
}
$spkac = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge);
if (!isset($spkac) || $spkac === false) {
$this->currentCert = false;
return false;
}
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
$algorithm = &$spkac['publicKeyAndChallenge']['spki']['algorithm']['algorithm'];
$key = &$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'];
$key = $this->_reformatKey($algorithm, $key);
switch ($algorithm) {
case 'rsaEncryption':
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$this->publicKey = new Crypt_RSA();
$this->publicKey->loadKey($key);
$this->publicKey->setPublicKey();
break;
default:
$this->publicKey = null;
}
$this->currentKeyIdentifier = null;
$this->currentCert = $spkac;
return $spkac;
}
/**
* Save a SPKAC CSR request
*
* @param array $csr
* @param int $format optional
* @access public
* @return string
*/
function saveSPKAC($spkac, $format = FILE_X509_FORMAT_PEM)
{
if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) {
return false;
}
$algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm');
switch (true) {
case !$algorithm:
case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']):
break;
default:
switch ($algorithm) {
case 'rsaEncryption':
$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'])));
}
}
$asn1 = new File_ASN1();
$asn1->loadOIDs($this->oids);
$spkac = $asn1->encodeDER($spkac, $this->SignedPublicKeyAndChallenge);
switch ($format) {
case FILE_X509_FORMAT_DER:
return $spkac;
// case FILE_X509_FORMAT_PEM:
default:
// OpenSSL's implementation of SPKAC requires the SPKAC be preceded by SPKAC= and since there are pretty much
// no other SPKAC decoders phpseclib will use that same format
return 'SPKAC=' . base64_encode($spkac);
}
}
/**
* Load a Certificate Revocation List
*
* @param string $crl
* @access public
* @return mixed
*/
function loadCRL($crl, $mode = FILE_X509_FORMAT_AUTO_DETECT)
{
if (is_array($crl) && isset($crl['tbsCertList'])) {
$this->currentCert = $crl;
unset($this->signatureSubject);
return $crl;
}
$asn1 = new File_ASN1();
if ($mode != FILE_X509_FORMAT_DER) {
$newcrl = $this->_extractBER($crl);
if ($mode == FILE_X509_FORMAT_PEM && $crl == $newcrl) {
return false;
}
$crl = $newcrl;
}
$orig = $crl;
if ($crl === false) {
$this->currentCert = false;
return false;
}
$asn1->loadOIDs($this->oids);
$decoded = $asn1->decodeBER($crl);
if (empty($decoded)) {
$this->currentCert = false;
return false;
}
$crl = $asn1->asn1map($decoded[0], $this->CertificateList);
if (!isset($crl) || $crl === false) {
$this->currentCert = false;
return false;
}
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
$this->_mapInDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
if ($this->_isSubArrayValid($crl, 'tbsCertList/crlExtensions')) {
$this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
}
if ($this->_isSubArrayValid($crl, 'tbsCertList/revokedCertificates')) {
$rclist_ref = &$this->_subArrayUnchecked($crl, 'tbsCertList/revokedCertificates');
if ($rclist_ref) {
$rclist = $crl['tbsCertList']['revokedCertificates'];
foreach ($rclist as $i => $extension) {
if ($this->_isSubArrayValid($rclist, "$i/crlEntryExtensions", $asn1)) {
$this->_mapInExtensions($rclist_ref, "$i/crlEntryExtensions", $asn1);
}
}
}
}
$this->currentKeyIdentifier = null;
$this->currentCert = $crl;
return $crl;
}
/**
* Save Certificate Revocation List.
*
* @param array $crl
* @param int $format optional
* @access public
* @return string
*/
function saveCRL($crl, $format = FILE_X509_FORMAT_PEM)
{
if (!is_array($crl) || !isset($crl['tbsCertList'])) {
return false;
}
$asn1 = new File_ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['tbsCertList']['issuer']['rdnSequence']['value']
= array('type' => FILE_ASN1_TYPE_UTF8_STRING);
$filters['tbsCertList']['signature']['parameters']
= array('type' => FILE_ASN1_TYPE_UTF8_STRING);
$filters['signatureAlgorithm']['parameters']
= array('type' => FILE_ASN1_TYPE_UTF8_STRING);
if (empty($crl['tbsCertList']['signature']['parameters'])) {
$filters['tbsCertList']['signature']['parameters']
= array('type' => FILE_ASN1_TYPE_NULL);
}
if (empty($crl['signatureAlgorithm']['parameters'])) {
$filters['signatureAlgorithm']['parameters']
= array('type' => FILE_ASN1_TYPE_NULL);
}
$asn1->loadFilters($filters);
$this->_mapOutDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
$this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
$rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates');
if (is_array($rclist)) {
foreach ($rclist as $i => $extension) {
$this->_mapOutExtensions($rclist, "$i/crlEntryExtensions", $asn1);
}
}
$crl = $asn1->encodeDER($crl, $this->CertificateList);
switch ($format) {
case FILE_X509_FORMAT_DER:
return $crl;
// case FILE_X509_FORMAT_PEM:
default:
return "-----BEGIN X509 CRL-----\r\n" . chunk_split(base64_encode($crl), 64) . '-----END X509 CRL-----';
}
}
/**
* Helper function to build a time field according to RFC 3280 section
* - 4.1.2.5 Validity
* - 5.1.2.4 This Update
* - 5.1.2.5 Next Update
* - 5.1.2.6 Revoked Certificates
* by choosing utcTime iff year of date given is before 2050 and generalTime else.
*
* @param string $date in format date('D, d M Y H:i:s O')
* @access private
* @return array
*/
function _timeField($date)
{
if (is_object($date) && strtolower(get_class($date)) == 'file_asn1_element') {
return $date;
}
if (!class_exists('DateTime')) {
$year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this
} else {
$dateObj = new DateTime($date, new DateTimeZone('GMT'));
$year = $dateObj->format('Y');
}
if ($year < 2050) {
return array('utcTime' => $date);
} else {
return array('generalTime' => $date);
}
}
/**
* Sign an X.509 certificate
*
* $issuer's private key needs to be loaded.
* $subject can be either an existing X.509 cert (if you want to resign it),
* a CSR or something with the DN and public key explicitly set.
*
* @param File_X509 $issuer
* @param File_X509 $subject
* @param string $signatureAlgorithm optional
* @access public
* @return mixed
*/
function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption')
{
if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
return false;
}
if (isset($subject->publicKey) && !($subjectPublicKey = $subject->_formatSubjectPublicKey())) {
return false;
}
$currentCert = isset($this->currentCert) ? $this->currentCert : null;
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
$this->currentCert = $subject->currentCert;
$this->currentCert['tbsCertificate']['signature']['algorithm'] = $signatureAlgorithm;
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
if (!empty($this->startDate)) {
$this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate);
}
if (!empty($this->endDate)) {
$this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate);
}
if (!empty($this->serialNumber)) {
$this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
}
if (!empty($subject->dn)) {
$this->currentCert['tbsCertificate']['subject'] = $subject->dn;
}
if (!empty($subject->publicKey)) {
$this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey;
}
$this->removeExtension('id-ce-authorityKeyIdentifier');
if (isset($subject->domains)) {
$this->removeExtension('id-ce-subjectAltName');
}
} elseif (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) {
return false;
} else {
if (!isset($subject->publicKey)) {
return false;
}
if (!class_exists('DateTime')) {
$startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
$endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year'));
} else {
$startDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
$startDate = !empty($this->startDate) ? $this->startDate : $startDate->format('D, d M Y H:i:s O');
$endDate = new DateTime('+1 year', new DateTimeZone(@date_default_timezone_get()));
$endDate = !empty($this->endDate) ? $this->endDate : $endDate->format('D, d M Y H:i:s O');
}
if (!empty($this->serialNumber)) {
$serialNumber = $this->serialNumber;
} else {
if (!function_exists('crypt_random_string')) {
include_once 'Crypt/Random.php';
}
/* "The serial number MUST be a positive integer"
"Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
-- https://tools.ietf.org/html/rfc5280#section-4.1.2.2
for the integer to be positive the leading bit needs to be 0 hence the
application of a bitmap
*/
$serialNumber = new Math_BigInteger(crypt_random_string(20) & ("\x7F" . str_repeat("\xFF", 19)), 256);
}
$this->currentCert = array(
'tbsCertificate' =>
array(
'version' => 'v3',
'serialNumber' => $serialNumber, // $this->setSerialNumber()
'signature' => array('algorithm' => $signatureAlgorithm),
'issuer' => false, // this is going to be overwritten later
'validity' => array(
'notBefore' => $this->_timeField($startDate), // $this->setStartDate()
'notAfter' => $this->_timeField($endDate) // $this->setEndDate()
),
'subject' => $subject->dn,
'subjectPublicKeyInfo' => $subjectPublicKey
),
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
'signature' => false // this is going to be overwritten later
);
// Copy extensions from CSR.
$csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0);
if (!empty($csrexts)) {
$this->currentCert['tbsCertificate']['extensions'] = $csrexts;
}
}
$this->currentCert['tbsCertificate']['issuer'] = $issuer->dn;
if (isset($issuer->currentKeyIdentifier)) {
$this->setExtension('id-ce-authorityKeyIdentifier', array(
//'authorityCertIssuer' => array(
// array(
// 'directoryName' => $issuer->dn
// )
//),
'keyIdentifier' => $issuer->currentKeyIdentifier
));
//$extensions = &$this->currentCert['tbsCertificate']['extensions'];
//if (isset($issuer->serialNumber)) {
// $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
//}
//unset($extensions);
}
if (isset($subject->currentKeyIdentifier)) {
$this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier);
}
$altName = array();
if (isset($subject->domains) && count($subject->domains)) {
$altName = array_map(array('File_X509', '_dnsName'), $subject->domains);
}
if (isset($subject->ipAddresses) && count($subject->ipAddresses)) {
// should an IP address appear as the CN if no domain name is specified? idk
//$ips = count($subject->domains) ? $subject->ipAddresses : array_slice($subject->ipAddresses, 1);
$ipAddresses = array();
foreach ($subject->ipAddresses as $ipAddress) {
$encoded = $subject->_ipAddress($ipAddress);
if ($encoded !== false) {
$ipAddresses[] = $encoded;
}
}
if (count($ipAddresses)) {
$altName = array_merge($altName, $ipAddresses);
}
}
if (!empty($altName)) {
$this->setExtension('id-ce-subjectAltName', $altName);
}
if ($this->caFlag) {
$keyUsage = $this->getExtension('id-ce-keyUsage');
if (!$keyUsage) {
$keyUsage = array();
}
$this->setExtension(
'id-ce-keyUsage',
array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign'))))
);
$basicConstraints = $this->getExtension('id-ce-basicConstraints');
if (!$basicConstraints) {
$basicConstraints = array();
}
$this->setExtension(
'id-ce-basicConstraints',
array_unique(array_merge(array('cA' => true), $basicConstraints)),
true
);
if (!isset($subject->currentKeyIdentifier)) {
$this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false);
}
}
// resync $this->signatureSubject
// save $tbsCertificate in case there are any File_ASN1_Element objects in it
$tbsCertificate = $this->currentCert['tbsCertificate'];
$this->loadX509($this->saveX509($this->currentCert));
$result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
$result['tbsCertificate'] = $tbsCertificate;
$this->currentCert = $currentCert;
$this->signatureSubject = $signatureSubject;
return $result;
}
/**
* Sign a CSR
*
* @access public
* @return mixed
*/
function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption')
{
if (!is_object($this->privateKey) || empty($this->dn)) {
return false;
}
$origPublicKey = $this->publicKey;
$class = get_class($this->privateKey);
$this->publicKey = new $class();
$this->publicKey->loadKey($this->privateKey->getPublicKey());
$this->publicKey->setPublicKey();
if (!($publicKey = $this->_formatSubjectPublicKey())) {
return false;
}
$this->publicKey = $origPublicKey;
$currentCert = isset($this->currentCert) ? $this->currentCert : null;
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) {
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
if (!empty($this->dn)) {
$this->currentCert['certificationRequestInfo']['subject'] = $this->dn;
}
$this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey;
} else {
$this->currentCert = array(
'certificationRequestInfo' =>
array(
'version' => 'v1',
'subject' => $this->dn,
'subjectPKInfo' => $publicKey
),
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
'signature' => false // this is going to be overwritten later
);
}
// resync $this->signatureSubject
// save $certificationRequestInfo in case there are any File_ASN1_Element objects in it
$certificationRequestInfo = $this->currentCert['certificationRequestInfo'];
$this->loadCSR($this->saveCSR($this->currentCert));
$result = $this->_sign($this->privateKey, $signatureAlgorithm);
$result['certificationRequestInfo'] = $certificationRequestInfo;
$this->currentCert = $currentCert;
$this->signatureSubject = $signatureSubject;
return $result;
}
/**
* Sign a SPKAC
*
* @access public
* @return mixed
*/
function signSPKAC($signatureAlgorithm = 'sha1WithRSAEncryption')
{
if (!is_object($this->privateKey)) {
return false;
}
$origPublicKey = $this->publicKey;
$class = get_class($this->privateKey);
$this->publicKey = new $class();
$this->publicKey->loadKey($this->privateKey->getPublicKey());
$this->publicKey->setPublicKey();
$publicKey = $this->_formatSubjectPublicKey();
if (!$publicKey) {
return false;
}
$this->publicKey = $origPublicKey;
$currentCert = isset($this->currentCert) ? $this->currentCert : null;
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
// re-signing a SPKAC seems silly but since everything else supports re-signing why not?
if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) {
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
$this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey;
if (!empty($this->challenge)) {
// the bitwise AND ensures that the output is a valid IA5String
$this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge));
}
} else {
$this->currentCert = array(
'publicKeyAndChallenge' =>
array(
'spki' => $publicKey,
// quoting ,
// "A challenge string that is submitted along with the public key. Defaults to an empty string if not specified."
// both Firefox and OpenSSL ("openssl spkac -key private.key") behave this way
// we could alternatively do this instead if we ignored the specs:
// crypt_random_string(8) & str_repeat("\x7F", 8)
'challenge' => !empty($this->challenge) ? $this->challenge : ''
),
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
'signature' => false // this is going to be overwritten later
);
}
// resync $this->signatureSubject
// save $publicKeyAndChallenge in case there are any File_ASN1_Element objects in it
$publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge'];
$this->loadSPKAC($this->saveSPKAC($this->currentCert));
$result = $this->_sign($this->privateKey, $signatureAlgorithm);
$result['publicKeyAndChallenge'] = $publicKeyAndChallenge;
$this->currentCert = $currentCert;
$this->signatureSubject = $signatureSubject;
return $result;
}
/**
* Sign a CRL
*
* $issuer's private key needs to be loaded.
*
* @param File_X509 $issuer
* @param File_X509 $crl
* @param string $signatureAlgorithm optional
* @access public
* @return mixed
*/
function signCRL($issuer, $crl, $signatureAlgorithm = 'sha1WithRSAEncryption')
{
if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
return false;
}
$currentCert = isset($this->currentCert) ? $this->currentCert : null;
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
if (!class_exists('DateTime')) {
$thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
} else {
$thisUpdate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
$thisUpdate = !empty($this->startDate) ? $this->startDate : $thisUpdate->format('D, d M Y H:i:s O');
}
if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
$this->currentCert = $crl->currentCert;
$this->currentCert['tbsCertList']['signature']['algorithm'] = $signatureAlgorithm;
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
} else {
$this->currentCert = array(
'tbsCertList' =>
array(
'version' => 'v2',
'signature' => array('algorithm' => $signatureAlgorithm),
'issuer' => false, // this is going to be overwritten later
'thisUpdate' => $this->_timeField($thisUpdate) // $this->setStartDate()
),
'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm),
'signature' => false // this is going to be overwritten later
);
}
$tbsCertList = &$this->currentCert['tbsCertList'];
$tbsCertList['issuer'] = $issuer->dn;
$tbsCertList['thisUpdate'] = $this->_timeField($thisUpdate);
if (!empty($this->endDate)) {
$tbsCertList['nextUpdate'] = $this->_timeField($this->endDate); // $this->setEndDate()
} else {
unset($tbsCertList['nextUpdate']);
}
if (!empty($this->serialNumber)) {
$crlNumber = $this->serialNumber;
} else {
$crlNumber = $this->getExtension('id-ce-cRLNumber');
// "The CRL number is a non-critical CRL extension that conveys a
// monotonically increasing sequence number for a given CRL scope and
// CRL issuer. This extension allows users to easily determine when a
// particular CRL supersedes another CRL."
// -- https://tools.ietf.org/html/rfc5280#section-5.2.3
$crlNumber = $crlNumber !== false ? $crlNumber->add(new Math_BigInteger(1)) : null;
}
$this->removeExtension('id-ce-authorityKeyIdentifier');
$this->removeExtension('id-ce-issuerAltName');
// Be sure version >= v2 if some extension found.
$version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0;
if (!$version) {
if (!empty($tbsCertList['crlExtensions'])) {
$version = 1; // v2.
} elseif (!empty($tbsCertList['revokedCertificates'])) {
foreach ($tbsCertList['revokedCertificates'] as $cert) {
if (!empty($cert['crlEntryExtensions'])) {
$version = 1; // v2.
}
}
}
if ($version) {
$tbsCertList['version'] = $version;
}
}
// Store additional extensions.
if (!empty($tbsCertList['version'])) { // At least v2.
if (!empty($crlNumber)) {
$this->setExtension('id-ce-cRLNumber', $crlNumber);
}
if (isset($issuer->currentKeyIdentifier)) {
$this->setExtension('id-ce-authorityKeyIdentifier', array(
//'authorityCertIssuer' => array(
// array(
// 'directoryName' => $issuer->dn
// )
//),
'keyIdentifier' => $issuer->currentKeyIdentifier
));
//$extensions = &$tbsCertList['crlExtensions'];
//if (isset($issuer->serialNumber)) {
// $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
//}
//unset($extensions);
}
$issuerAltName = $this->getExtension('id-ce-subjectAltName', $issuer->currentCert);
if ($issuerAltName !== false) {
$this->setExtension('id-ce-issuerAltName', $issuerAltName);
}
}
if (empty($tbsCertList['revokedCertificates'])) {
unset($tbsCertList['revokedCertificates']);
}
unset($tbsCertList);
// resync $this->signatureSubject
// save $tbsCertList in case there are any File_ASN1_Element objects in it
$tbsCertList = $this->currentCert['tbsCertList'];
$this->loadCRL($this->saveCRL($this->currentCert));
$result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
$result['tbsCertList'] = $tbsCertList;
$this->currentCert = $currentCert;
$this->signatureSubject = $signatureSubject;
return $result;
}
/**
* X.509 certificate signing helper function.
*
* @param object $key
* @param File_X509 $subject
* @param string $signatureAlgorithm
* @access public
* @return mixed
*/
function _sign($key, $signatureAlgorithm)
{
switch (strtolower(get_class($key))) {
case 'crypt_rsa':
switch ($signatureAlgorithm) {
case 'md2WithRSAEncryption':
case 'md5WithRSAEncryption':
case 'sha1WithRSAEncryption':
case 'sha224WithRSAEncryption':
case 'sha256WithRSAEncryption':
case 'sha384WithRSAEncryption':
case 'sha512WithRSAEncryption':
$key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
$key->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject));
return $this->currentCert;
}
default:
return false;
}
}
/**
* Set certificate start date
*
* @param string $date
* @access public
*/
function setStartDate($date)
{
if (class_exists('DateTime')) {
$date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
$this->startDate = $date->format('D, d M Y H:i:s O');
} else {
$this->startDate = @date('D, d M Y H:i:s O', @strtotime($date));
}
}
/**
* Set certificate end date
*
* @param string $date
* @access public
*/
function setEndDate($date)
{
/*
To indicate that a certificate has no well-defined expiration date,
the notAfter SHOULD be assigned the GeneralizedTime value of
99991231235959Z.
-- http://tools.ietf.org/html/rfc5280#section-4.1.2.5
*/
if (strtolower($date) == 'lifetime') {
$temp = '99991231235959Z';
$asn1 = new File_ASN1();
$temp = chr(FILE_ASN1_TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
$this->endDate = new File_ASN1_Element($temp);
} else {
if (class_exists('DateTime')) {
$date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
$this->endDate = $date->format('D, d M Y H:i:s O');
} else {
$this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
}
}
}
/**
* Set Serial Number
*
* @param string $serial
* @param $base optional
* @access public
*/
function setSerialNumber($serial, $base = -256)
{
$this->serialNumber = new Math_BigInteger($serial, $base);
}
/**
* Turns the certificate into a certificate authority
*
* @access public
*/
function makeCA()
{
$this->caFlag = true;
}
/**
* Check for validity of subarray
*
* This is intended for use in conjunction with _subArrayUnchecked(),
* implementing the checks included in _subArray() but without copying
* a potentially large array by passing its reference by-value to is_array().
*
* @param array $root
* @param string $path
* @return boolean
* @access private
*/
function _isSubArrayValid($root, $path)
{
if (!is_array($root)) {
return false;
}
foreach (explode('/', $path) as $i) {
if (!is_array($root)) {
return false;
}
if (!isset($root[$i])) {
return true;
}
$root = $root[$i];
}
return true;
}
/**
* Get a reference to a subarray
*
* This variant of _subArray() does no is_array() checking,
* so $root should be checked with _isSubArrayValid() first.
*
* This is here for performance reasons:
* Passing a reference (i.e. $root) by-value (i.e. to is_array())
* creates a copy. If $root is an especially large array, this is expensive.
*
* @param array $root
* @param string $path absolute path with / as component separator
* @param bool $create optional
* @access private
* @return array|false
*/
function &_subArrayUnchecked(&$root, $path, $create = false)
{
$false = false;
foreach (explode('/', $path) as $i) {
if (!isset($root[$i])) {
if (!$create) {
return $false;
}
$root[$i] = array();
}
$root = &$root[$i];
}
return $root;
}
/**
* Get a reference to a subarray
*
* @param array $root
* @param string $path absolute path with / as component separator
* @param bool $create optional
* @access private
* @return array|false
*/
function &_subArray(&$root, $path, $create = false)
{
$false = false;
if (!is_array($root)) {
return $false;
}
foreach (explode('/', $path) as $i) {
if (!is_array($root)) {
return $false;
}
if (!isset($root[$i])) {
if (!$create) {
return $false;
}
$root[$i] = array();
}
$root = &$root[$i];
}
return $root;
}
/**
* Get a reference to an extension subarray
*
* @param array $root
* @param string $path optional absolute path with / as component separator
* @param bool $create optional
* @access private
* @return array|false
*/
function &_extensions(&$root, $path = null, $create = false)
{
if (!isset($root)) {
$root = $this->currentCert;
}
switch (true) {
case !empty($path):
case !is_array($root):
break;
case isset($root['tbsCertificate']):
$path = 'tbsCertificate/extensions';
break;
case isset($root['tbsCertList']):
$path = 'tbsCertList/crlExtensions';
break;
case isset($root['certificationRequestInfo']):
$pth = 'certificationRequestInfo/attributes';
$attributes = &$this->_subArray($root, $pth, $create);
if (is_array($attributes)) {
foreach ($attributes as $key => $value) {
if ($value['type'] == 'pkcs-9-at-extensionRequest') {
$path = "$pth/$key/value/0";
break 2;
}
}
if ($create) {
$key = count($attributes);
$attributes[] = array('type' => 'pkcs-9-at-extensionRequest', 'value' => array());
$path = "$pth/$key/value/0";
}
}
break;
}
$extensions = &$this->_subArray($root, $path, $create);
if (!is_array($extensions)) {
$false = false;
return $false;
}
return $extensions;
}
/**
* Remove an Extension
*
* @param string $id
* @param string $path optional
* @access private
* @return bool
*/
function _removeExtension($id, $path = null)
{
$extensions = &$this->_extensions($this->currentCert, $path);
if (!is_array($extensions)) {
return false;
}
$result = false;
foreach ($extensions as $key => $value) {
if ($value['extnId'] == $id) {
unset($extensions[$key]);
$result = true;
}
}
$extensions = array_values($extensions);
// fix for https://bugs.php.net/75433 affecting PHP 7.2
if (!isset($extensions[0])) {
$extensions = array_splice($extensions, 0, 0);
}
return $result;
}
/**
* Get an Extension
*
* Returns the extension if it exists and false if not
*
* @param string $id
* @param array $cert optional
* @param string $path optional
* @access private
* @return mixed
*/
function _getExtension($id, $cert = null, $path = null)
{
$extensions = $this->_extensions($cert, $path);
if (!is_array($extensions)) {
return false;
}
foreach ($extensions as $key => $value) {
if ($value['extnId'] == $id) {
return $value['extnValue'];
}
}
return false;
}
/**
* Returns a list of all extensions in use
*
* @param array $cert optional
* @param string $path optional
* @access private
* @return array
*/
function _getExtensions($cert = null, $path = null)
{
$exts = $this->_extensions($cert, $path);
$extensions = array();
if (is_array($exts)) {
foreach ($exts as $extension) {
$extensions[] = $extension['extnId'];
}
}
return $extensions;
}
/**
* Set an Extension
*
* @param string $id
* @param mixed $value
* @param bool $critical optional
* @param bool $replace optional
* @param string $path optional
* @access private
* @return bool
*/
function _setExtension($id, $value, $critical = false, $replace = true, $path = null)
{
$extensions = &$this->_extensions($this->currentCert, $path, true);
if (!is_array($extensions)) {
return false;
}
$newext = array('extnId' => $id, 'critical' => $critical, 'extnValue' => $value);
foreach ($extensions as $key => $value) {
if ($value['extnId'] == $id) {
if (!$replace) {
return false;
}
$extensions[$key] = $newext;
return true;
}
}
$extensions[] = $newext;
return true;
}
/**
* Remove a certificate, CSR or CRL Extension
*
* @param string $id
* @access public
* @return bool
*/
function removeExtension($id)
{
return $this->_removeExtension($id);
}
/**
* Get a certificate, CSR or CRL Extension
*
* Returns the extension if it exists and false if not
*
* @param string $id
* @param array $cert optional
* @access public
* @return mixed
*/
function getExtension($id, $cert = null)
{
return $this->_getExtension($id, $cert);
}
/**
* Returns a list of all extensions in use in certificate, CSR or CRL
*
* @param array $cert optional
* @access public
* @return array
*/
function getExtensions($cert = null)
{
return $this->_getExtensions($cert);
}
/**
* Set a certificate, CSR or CRL Extension
*
* @param string $id
* @param mixed $value
* @param bool $critical optional
* @param bool $replace optional
* @access public
* @return bool
*/
function setExtension($id, $value, $critical = false, $replace = true)
{
return $this->_setExtension($id, $value, $critical, $replace);
}
/**
* Remove a CSR attribute.
*
* @param string $id
* @param int $disposition optional
* @access public
* @return bool
*/
function removeAttribute($id, $disposition = FILE_X509_ATTR_ALL)
{
$attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes');
if (!is_array($attributes)) {
return false;
}
$result = false;
foreach ($attributes as $key => $attribute) {
if ($attribute['type'] == $id) {
$n = count($attribute['value']);
switch (true) {
case $disposition == FILE_X509_ATTR_APPEND:
case $disposition == FILE_X509_ATTR_REPLACE:
return false;
case $disposition >= $n:
$disposition -= $n;
break;
case $disposition == FILE_X509_ATTR_ALL:
case $n == 1:
unset($attributes[$key]);
$result = true;
break;
default:
unset($attributes[$key]['value'][$disposition]);
$attributes[$key]['value'] = array_values($attributes[$key]['value']);
$result = true;
break;
}
if ($result && $disposition != FILE_X509_ATTR_ALL) {
break;
}
}
}
$attributes = array_values($attributes);
return $result;
}
/**
* Get a CSR attribute
*
* Returns the attribute if it exists and false if not
*
* @param string $id
* @param int $disposition optional
* @param array $csr optional
* @access public
* @return mixed
*/
function getAttribute($id, $disposition = FILE_X509_ATTR_ALL, $csr = null)
{
if (empty($csr)) {
$csr = $this->currentCert;
}
$attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
if (!is_array($attributes)) {
return false;
}
foreach ($attributes as $key => $attribute) {
if ($attribute['type'] == $id) {
$n = count($attribute['value']);
switch (true) {
case $disposition == FILE_X509_ATTR_APPEND:
case $disposition == FILE_X509_ATTR_REPLACE:
return false;
case $disposition == FILE_X509_ATTR_ALL:
return $attribute['value'];
case $disposition >= $n:
$disposition -= $n;
break;
default:
return $attribute['value'][$disposition];
}
}
}
return false;
}
/**
* Returns a list of all CSR attributes in use
*
* @param array $csr optional
* @access public
* @return array
*/
function getAttributes($csr = null)
{
if (empty($csr)) {
$csr = $this->currentCert;
}
$attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes');
$attrs = array();
if (is_array($attributes)) {
foreach ($attributes as $attribute) {
$attrs[] = $attribute['type'];
}
}
return $attrs;
}
/**
* Set a CSR attribute
*
* @param string $id
* @param mixed $value
* @param bool $disposition optional
* @access public
* @return bool
*/
function setAttribute($id, $value, $disposition = FILE_X509_ATTR_ALL)
{
$attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes', true);
if (!is_array($attributes)) {
return false;
}
switch ($disposition) {
case FILE_X509_ATTR_REPLACE:
$disposition = FILE_X509_ATTR_APPEND;
case FILE_X509_ATTR_ALL:
$this->removeAttribute($id);
break;
}
foreach ($attributes as $key => $attribute) {
if ($attribute['type'] == $id) {
$n = count($attribute['value']);
switch (true) {
case $disposition == FILE_X509_ATTR_APPEND:
$last = $key;
break;
case $disposition >= $n:
$disposition -= $n;
break;
default:
$attributes[$key]['value'][$disposition] = $value;
return true;
}
}
}
switch (true) {
case $disposition >= 0:
return false;
case isset($last):
$attributes[$last]['value'][] = $value;
break;
default:
$attributes[] = array('type' => $id, 'value' => $disposition == FILE_X509_ATTR_ALL ? $value: array($value));
break;
}
return true;
}
/**
* Sets the subject key identifier
*
* This is used by the id-ce-authorityKeyIdentifier and the id-ce-subjectKeyIdentifier extensions.
*
* @param string $value
* @access public
*/
function setKeyIdentifier($value)
{
if (empty($value)) {
unset($this->currentKeyIdentifier);
} else {
$this->currentKeyIdentifier = base64_encode($value);
}
}
/**
* Compute a public key identifier.
*
* Although key identifiers may be set to any unique value, this function
* computes key identifiers from public key according to the two
* recommended methods (4.2.1.2 RFC 3280).
* Highly polymorphic: try to accept all possible forms of key:
* - Key object
* - File_X509 object with public or private key defined
* - Certificate or CSR array
* - File_ASN1_Element object
* - PEM or DER string
*
* @param mixed $key optional
* @param int $method optional
* @access public
* @return string binary key identifier
*/
function computeKeyIdentifier($key = null, $method = 1)
{
if (is_null($key)) {
$key = $this;
}
switch (true) {
case is_string($key):
break;
case is_array($key) && isset($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
return $this->computeKeyIdentifier($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $method);
case is_array($key) && isset($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
return $this->computeKeyIdentifier($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $method);
case !is_object($key):
return false;
case strtolower(get_class($key)) == 'file_asn1_element':
// Assume the element is a bitstring-packed key.
$asn1 = new File_ASN1();
$decoded = $asn1->decodeBER($key->element);
if (empty($decoded)) {
return false;
}
$raw = $asn1->asn1map($decoded[0], array('type' => FILE_ASN1_TYPE_BIT_STRING));
if (empty($raw)) {
return false;
}
$raw = base64_decode($raw);
// If the key is private, compute identifier from its corresponding public key.
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$key = new Crypt_RSA();
if (!$key->loadKey($raw)) {
return false; // Not an unencrypted RSA key.
}
if ($key->getPrivateKey() !== false) { // If private.
return $this->computeKeyIdentifier($key, $method);
}
$key = $raw; // Is a public key.
break;
case strtolower(get_class($key)) == 'file_x509':
if (isset($key->publicKey)) {
return $this->computeKeyIdentifier($key->publicKey, $method);
}
if (isset($key->privateKey)) {
return $this->computeKeyIdentifier($key->privateKey, $method);
}
if (isset($key->currentCert['tbsCertificate']) || isset($key->currentCert['certificationRequestInfo'])) {
return $this->computeKeyIdentifier($key->currentCert, $method);
}
return false;
default: // Should be a key object (i.e.: Crypt_RSA).
$key = $key->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
break;
}
// If in PEM format, convert to binary.
$key = $this->_extractBER($key);
// Now we have the key string: compute its sha-1 sum.
if (!class_exists('Crypt_Hash')) {
include_once 'Crypt/Hash.php';
}
$hash = new Crypt_Hash('sha1');
$hash = $hash->hash($key);
if ($method == 2) {
$hash = substr($hash, -8);
$hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40);
}
return $hash;
}
/**
* Format a public key as appropriate
*
* @access private
* @return array
*/
function _formatSubjectPublicKey()
{
if (!isset($this->publicKey) || !is_object($this->publicKey)) {
return false;
}
switch (strtolower(get_class($this->publicKey))) {
case 'crypt_rsa':
// the following two return statements do the same thing. i dunno.. i just prefer the later for some reason.
// the former is a good example of how to do fuzzing on the public key
//return new File_ASN1_Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())));
return array(
'algorithm' => array('algorithm' => 'rsaEncryption'),
'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
);
default:
return false;
}
}
/**
* Set the domain name's which the cert is to be valid for
*
* @access public
* @return array
*/
function setDomain()
{
$this->domains = func_get_args();
$this->removeDNProp('id-at-commonName');
$this->setDNProp('id-at-commonName', $this->domains[0]);
}
/**
* Set the IP Addresses's which the cert is to be valid for
*
* @access public
* @param string $ipAddress optional
*/
function setIPAddress()
{
$this->ipAddresses = func_get_args();
/*
if (!isset($this->domains)) {
$this->removeDNProp('id-at-commonName');
$this->setDNProp('id-at-commonName', $this->ipAddresses[0]);
}
*/
}
/**
* Helper function to build domain array
*
* @access private
* @param string $domain
* @return array
*/
function _dnsName($domain)
{
return array('dNSName' => $domain);
}
/**
* Helper function to build IP Address array
*
* (IPv6 is not currently supported)
*
* @access private
* @param string $address
* @return array
*/
function _iPAddress($address)
{
return array('iPAddress' => $address);
}
/**
* Get the index of a revoked certificate.
*
* @param array $rclist
* @param string $serial
* @param bool $create optional
* @access private
* @return int|false
*/
function _revokedCertificate(&$rclist, $serial, $create = false)
{
$serial = new Math_BigInteger($serial);
foreach ($rclist as $i => $rc) {
if (!($serial->compare($rc['userCertificate']))) {
return $i;
}
}
if (!$create) {
return false;
}
if (!class_exists('DateTime')) {
$revocationDate = @date('D, d M Y H:i:s O');
} else {
$revocationDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
$revocationDate = $revocationDate->format('D, d M Y H:i:s O');
}
$i = count($rclist);
$rclist[] = array('userCertificate' => $serial,
'revocationDate' => $this->_timeField($revocationDate));
return $i;
}
/**
* Revoke a certificate.
*
* @param string $serial
* @param string $date optional
* @access public
* @return bool
*/
function revoke($serial, $date = null)
{
if (isset($this->currentCert['tbsCertList'])) {
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
if ($this->_revokedCertificate($rclist, $serial) === false) { // If not yet revoked
if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
if (!empty($date)) {
$rclist[$i]['revocationDate'] = $this->_timeField($date);
}
return true;
}
}
}
}
return false;
}
/**
* Unrevoke a certificate.
*
* @param string $serial
* @access public
* @return bool
*/
function unrevoke($serial)
{
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
unset($rclist[$i]);
$rclist = array_values($rclist);
return true;
}
}
return false;
}
/**
* Get a revoked certificate.
*
* @param string $serial
* @access public
* @return mixed
*/
function getRevoked($serial)
{
if (is_array($rclist = $this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
return $rclist[$i];
}
}
return false;
}
/**
* List revoked certificates
*
* @param array $crl optional
* @access public
* @return array
*/
function listRevoked($crl = null)
{
if (!isset($crl)) {
$crl = $this->currentCert;
}
if (!isset($crl['tbsCertList'])) {
return false;
}
$result = array();
if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
foreach ($rclist as $rc) {
$result[] = $rc['userCertificate']->toString();
}
}
return $result;
}
/**
* Remove a Revoked Certificate Extension
*
* @param string $serial
* @param string $id
* @access public
* @return bool
*/
function removeRevokedCertificateExtension($serial, $id)
{
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
return $this->_removeExtension($id, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
}
}
return false;
}
/**
* Get a Revoked Certificate Extension
*
* Returns the extension if it exists and false if not
*
* @param string $serial
* @param string $id
* @param array $crl optional
* @access public
* @return mixed
*/
function getRevokedCertificateExtension($serial, $id, $crl = null)
{
if (!isset($crl)) {
$crl = $this->currentCert;
}
if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
return $this->_getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
}
}
return false;
}
/**
* Returns a list of all extensions in use for a given revoked certificate
*
* @param string $serial
* @param array $crl optional
* @access public
* @return array
*/
function getRevokedCertificateExtensions($serial, $crl = null)
{
if (!isset($crl)) {
$crl = $this->currentCert;
}
if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) {
if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) {
return $this->_getExtensions($crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
}
}
return false;
}
/**
* Set a Revoked Certificate Extension
*
* @param string $serial
* @param string $id
* @param mixed $value
* @param bool $critical optional
* @param bool $replace optional
* @access public
* @return bool
*/
function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true)
{
if (isset($this->currentCert['tbsCertList'])) {
if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) {
return $this->_setExtension($id, $value, $critical, $replace, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
}
}
}
return false;
}
/**
* Extract raw BER from Base64 encoding
*
* @access private
* @param string $str
* @return string
*/
function _extractBER($str)
{
/* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
* above and beyond the ceritificate.
* ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
*
* Bag Attributes
* localKeyID: 01 00 00 00
* subject=/O=organization/OU=org unit/CN=common name
* issuer=/O=organization/CN=common name
*/
$temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
// remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
$temp = preg_replace('#-+[^-]+-+#', '', $temp);
// remove new lines
$temp = str_replace(array("\r", "\n", ' '), '', $temp);
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
return $temp != false ? $temp : $str;
}
/**
* Returns the OID corresponding to a name
*
* What's returned in the associative array returned by loadX509() (or load*()) is either a name or an OID if
* no OID to name mapping is available. The problem with this is that what may be an unmapped OID in one version
* of phpseclib may not be unmapped in the next version, so apps that are looking at this OID may not be able
* to work from version to version.
*
* This method will return the OID if a name is passed to it and if no mapping is avialable it'll assume that
* what's being passed to it already is an OID and return that instead. A few examples.
*
* getOID('2.16.840.1.101.3.4.2.1') == '2.16.840.1.101.3.4.2.1'
* getOID('id-sha256') == '2.16.840.1.101.3.4.2.1'
* getOID('zzz') == 'zzz'
*
* @access public
* @return string
*/
function getOID($name)
{
static $reverseMap;
if (!isset($reverseMap)) {
$reverseMap = array_flip($this->oids);
}
return isset($reverseMap[$name]) ? $reverseMap[$name] : $name;
}
}
================================================
FILE: assets/libraries/phpseclib/Math/BigInteger.php
================================================
> and << cannot be used, nor can the modulo operator %,
* which only supports integers. Although this fact will slow this library down, the fact that such a high
* base is being used should more than compensate.
*
* Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie.
* (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
*
* Useful resources are as follows:
*
* - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
* - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
* - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
*
* Here's an example of how to use this library:
*
* add($b);
*
* echo $c->toString(); // outputs 5
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Math
* @package Math_BigInteger
* @author Jim Wigginton
* @copyright 2006 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
/**#@+
* Reduction constants
*
* @access private
* @see self::_reduce()
*/
/**
* @see self::_montgomery()
* @see self::_prepMontgomery()
*/
define('MATH_BIGINTEGER_MONTGOMERY', 0);
/**
* @see self::_barrett()
*/
define('MATH_BIGINTEGER_BARRETT', 1);
/**
* @see self::_mod2()
*/
define('MATH_BIGINTEGER_POWEROF2', 2);
/**
* @see self::_remainder()
*/
define('MATH_BIGINTEGER_CLASSIC', 3);
/**
* @see self::__clone()
*/
define('MATH_BIGINTEGER_NONE', 4);
/**#@-*/
/**#@+
* Array constants
*
* Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and
* multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
*
* @access private
*/
/**
* $result[MATH_BIGINTEGER_VALUE] contains the value.
*/
define('MATH_BIGINTEGER_VALUE', 0);
/**
* $result[MATH_BIGINTEGER_SIGN] contains the sign.
*/
define('MATH_BIGINTEGER_SIGN', 1);
/**#@-*/
/**#@+
* @access private
* @see self::_montgomery()
* @see self::_barrett()
*/
/**
* Cache constants
*
* $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
*/
define('MATH_BIGINTEGER_VARIABLE', 0);
/**
* $cache[MATH_BIGINTEGER_DATA] contains the cached data.
*/
define('MATH_BIGINTEGER_DATA', 1);
/**#@-*/
/**#@+
* Mode constants.
*
* @access private
* @see self::Math_BigInteger()
*/
/**
* To use the pure-PHP implementation
*/
define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
/**
* To use the BCMath library
*
* (if enabled; otherwise, the internal implementation will be used)
*/
define('MATH_BIGINTEGER_MODE_BCMATH', 2);
/**
* To use the GMP library
*
* (if present; otherwise, either the BCMath or the internal implementation will be used)
*/
define('MATH_BIGINTEGER_MODE_GMP', 3);
/**#@-*/
/**
* Karatsuba Cutoff
*
* At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
*
* @access private
*/
define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
/**
* Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
* numbers.
*
* @package Math_BigInteger
* @author Jim Wigginton
* @access public
*/
class Math_BigInteger
{
/**
* Holds the BigInteger's value.
*
* @var array
* @access private
*/
var $value;
/**
* Holds the BigInteger's magnitude.
*
* @var bool
* @access private
*/
var $is_negative = false;
/**
* Precision
*
* @see self::setPrecision()
* @access private
*/
var $precision = -1;
/**
* Precision Bitmask
*
* @see self::setPrecision()
* @access private
*/
var $bitmask = false;
/**
* Mode independent value used for serialization.
*
* If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
* a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
* however, $this->hex is only calculated when $this->__sleep() is called.
*
* @see self::__sleep()
* @see self::__wakeup()
* @var string
* @access private
*/
var $hex;
/**
* Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
*
* If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
* two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
*
* Here's an example:
*
* toString(); // outputs 50
* ?>
*
*
* @param $x base-10 number or base-$base number if $base set.
* @param int $base
* @return Math_BigInteger
* @access public
*/
function __construct($x = 0, $base = 10)
{
if (!defined('MATH_BIGINTEGER_MODE')) {
switch (true) {
case extension_loaded('gmp'):
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
break;
case extension_loaded('bcmath'):
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
break;
default:
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
}
}
if (extension_loaded('openssl') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
ob_start();
@phpinfo();
$content = ob_get_contents();
ob_end_clean();
preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
$versions = array();
if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) {
$fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
// Remove letter part in OpenSSL version
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
}
}
// it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
switch (true) {
case !isset($versions['Header']):
case !isset($versions['Library']):
case $versions['Header'] == $versions['Library']:
case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
break;
default:
define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
}
}
if (!defined('PHP_INT_SIZE')) {
define('PHP_INT_SIZE', 4);
}
if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) {
switch (PHP_INT_SIZE) {
case 8: // use 64-bit integers if int size is 8 bytes
define('MATH_BIGINTEGER_BASE', 31);
define('MATH_BIGINTEGER_BASE_FULL', 0x80000000);
define('MATH_BIGINTEGER_MAX_DIGIT', 0x7FFFFFFF);
define('MATH_BIGINTEGER_MSB', 0x40000000);
// 10**9 is the closest we can get to 2**31 without passing it
define('MATH_BIGINTEGER_MAX10', 1000000000);
define('MATH_BIGINTEGER_MAX10_LEN', 9);
// the largest digit that may be used in addition / subtraction
define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62));
break;
//case 4: // use 64-bit floats if int size is 4 bytes
default:
define('MATH_BIGINTEGER_BASE', 26);
define('MATH_BIGINTEGER_BASE_FULL', 0x4000000);
define('MATH_BIGINTEGER_MAX_DIGIT', 0x3FFFFFF);
define('MATH_BIGINTEGER_MSB', 0x2000000);
// 10**7 is the closest to 2**26 without passing it
define('MATH_BIGINTEGER_MAX10', 10000000);
define('MATH_BIGINTEGER_MAX10_LEN', 7);
// the largest digit that may be used in addition / subtraction
// we do pow(2, 52) instead of using 4503599627370496 directly because some
// PHP installations will truncate 4503599627370496.
define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52));
}
}
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
switch (true) {
case is_resource($x) && get_resource_type($x) == 'GMP integer':
// PHP 5.6 switched GMP from using resources to objects
case is_object($x) && get_class($x) == 'GMP':
$this->value = $x;
return;
}
$this->value = gmp_init(0);
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$this->value = '0';
break;
default:
$this->value = array();
}
// '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
// '0' is the only value like this per http://php.net/empty
if (empty($x) && (abs($base) != 256 || $x !== '0')) {
return;
}
switch ($base) {
case -256:
if (ord($x[0]) & 0x80) {
$x = ~$x;
$this->is_negative = true;
}
case 256:
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$this->value = function_exists('gmp_import') ?
gmp_import($x) :
gmp_init('0x' . bin2hex($x));
if ($this->is_negative) {
$this->value = gmp_neg($this->value);
}
break;
case MATH_BIGINTEGER_MODE_BCMATH:
// round $len to the nearest 4 (thanks, DavidMJ!)
$len = (strlen($x) + 3) & 0xFFFFFFFC;
$x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
for ($i = 0; $i < $len; $i+= 4) {
$this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
$this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
}
if ($this->is_negative) {
$this->value = '-' . $this->value;
}
break;
// converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
default:
while (strlen($x)) {
$this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE));
}
}
if ($this->is_negative) {
if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
$this->is_negative = false;
}
$temp = $this->add(new Math_BigInteger('-1'));
$this->value = $temp->value;
}
break;
case 16:
case -16:
if ($base > 0 && $x[0] == '-') {
$this->is_negative = true;
$x = substr($x, 1);
}
$x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
$is_negative = false;
if ($base < 0 && hexdec($x[0]) >= 8) {
$this->is_negative = $is_negative = true;
$x = bin2hex(~pack('H*', $x));
}
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
$this->value = gmp_init($temp);
$this->is_negative = false;
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$x = (strlen($x) & 1) ? '0' . $x : $x;
$temp = new Math_BigInteger(pack('H*', $x), 256);
$this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
$this->is_negative = false;
break;
default:
$x = (strlen($x) & 1) ? '0' . $x : $x;
$temp = new Math_BigInteger(pack('H*', $x), 256);
$this->value = $temp->value;
}
if ($is_negative) {
$temp = $this->add(new Math_BigInteger('-1'));
$this->value = $temp->value;
}
break;
case 10:
case -10:
// (?value = gmp_init($x);
break;
case MATH_BIGINTEGER_MODE_BCMATH:
// explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
// results then doing it on '-1' does (modInverse does $x[0])
$this->value = $x === '-' ? '0' : (string) $x;
break;
default:
$temp = new Math_BigInteger();
$multiplier = new Math_BigInteger();
$multiplier->value = array(MATH_BIGINTEGER_MAX10);
if ($x[0] == '-') {
$this->is_negative = true;
$x = substr($x, 1);
}
$x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT);
while (strlen($x)) {
$temp = $temp->multiply($multiplier);
$temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));
$x = substr($x, MATH_BIGINTEGER_MAX10_LEN);
}
$this->value = $temp->value;
}
break;
case 2: // base-2 support originally implemented by Lluis Pamies - thanks!
case -2:
if ($base > 0 && $x[0] == '-') {
$this->is_negative = true;
$x = substr($x, 1);
}
$x = preg_replace('#^([01]*).*#', '$1', $x);
$x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
$str = '0x';
while (strlen($x)) {
$part = substr($x, 0, 4);
$str.= dechex(bindec($part));
$x = substr($x, 4);
}
if ($this->is_negative) {
$str = '-' . $str;
}
$temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
$this->value = $temp->value;
$this->is_negative = $temp->is_negative;
break;
default:
// base not supported, so we'll let $this == 0
}
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param $x base-10 number or base-$base number if $base set.
* @param int $base
* @access public
*/
function Math_BigInteger($x = 0, $base = 10)
{
$this->__construct($x, $base);
}
/**
* Converts a BigInteger to a byte string (eg. base-256).
*
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
* saved as two's compliment.
*
* Here's an example:
*
* toBytes(); // outputs chr(65)
* ?>
*
*
* @param bool $twos_compliment
* @return string
* @access public
* @internal Converts a base-2**26 number to base-2**8
*/
function toBytes($twos_compliment = false)
{
if ($twos_compliment) {
$comparison = $this->compare(new Math_BigInteger());
if ($comparison == 0) {
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
}
$temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
$bytes = $temp->toBytes();
if (!strlen($bytes)) { // eg. if the number we're trying to convert is -1
$bytes = chr(0);
}
if (ord($bytes[0]) & 0x80) {
$bytes = chr(0) . $bytes;
}
return $comparison < 0 ? ~$bytes : $bytes;
}
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
if (gmp_cmp($this->value, gmp_init(0)) == 0) {
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
}
if (function_exists('gmp_export')) {
$temp = gmp_export($this->value);
} else {
$temp = gmp_strval(gmp_abs($this->value), 16);
$temp = (strlen($temp) & 1) ? '0' . $temp : $temp;
$temp = pack('H*', $temp);
}
return $this->precision > 0 ?
substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
ltrim($temp, chr(0));
case MATH_BIGINTEGER_MODE_BCMATH:
if ($this->value === '0') {
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
}
$value = '';
$current = $this->value;
if ($current[0] == '-') {
$current = substr($current, 1);
}
while (bccomp($current, '0', 0) > 0) {
$temp = bcmod($current, '16777216');
$value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
$current = bcdiv($current, '16777216', 0);
}
return $this->precision > 0 ?
substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
ltrim($value, chr(0));
}
if (!count($this->value)) {
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
}
$result = $this->_int2bytes($this->value[count($this->value) - 1]);
$temp = $this->copy();
for ($i = count($temp->value) - 2; $i >= 0; --$i) {
$temp->_base256_lshift($result, MATH_BIGINTEGER_BASE);
$result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
}
return $this->precision > 0 ?
str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
$result;
}
/**
* Converts a BigInteger to a hex string (eg. base-16)).
*
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
* saved as two's compliment.
*
* Here's an example:
*
* toHex(); // outputs '41'
* ?>
*
*
* @param bool $twos_compliment
* @return string
* @access public
* @internal Converts a base-2**26 number to base-2**8
*/
function toHex($twos_compliment = false)
{
return bin2hex($this->toBytes($twos_compliment));
}
/**
* Converts a BigInteger to a bit string (eg. base-2).
*
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
* saved as two's compliment.
*
* Here's an example:
*
* toBits(); // outputs '1000001'
* ?>
*
*
* @param bool $twos_compliment
* @return string
* @access public
* @internal Converts a base-2**26 number to base-2**2
*/
function toBits($twos_compliment = false)
{
$hex = $this->toHex($twos_compliment);
$bits = '';
for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
$bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
}
if ($start) { // hexdec('') == 0
$bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
}
$result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) {
return '0' . $result;
}
return $result;
}
/**
* Converts a BigInteger to a base-10 number.
*
* Here's an example:
*
* toString(); // outputs 50
* ?>
*
*
* @return string
* @access public
* @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
*/
function toString()
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
return gmp_strval($this->value);
case MATH_BIGINTEGER_MODE_BCMATH:
if ($this->value === '0') {
return '0';
}
return ltrim($this->value, '0');
}
if (!count($this->value)) {
return '0';
}
$temp = $this->copy();
$temp->is_negative = false;
$divisor = new Math_BigInteger();
$divisor->value = array(MATH_BIGINTEGER_MAX10);
$result = '';
while (count($temp->value)) {
list($temp, $mod) = $temp->divide($divisor);
$result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result;
}
$result = ltrim($result, '0');
if (empty($result)) {
$result = '0';
}
if ($this->is_negative) {
$result = '-' . $result;
}
return $result;
}
/**
* Copy an object
*
* PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee
* that all objects are passed by value, when appropriate. More information can be found here:
*
* {@link http://php.net/language.oop5.basic#51624}
*
* @access public
* @see self::__clone()
* @return Math_BigInteger
*/
function copy()
{
$temp = new Math_BigInteger();
$temp->value = $this->value;
$temp->is_negative = $this->is_negative;
$temp->precision = $this->precision;
$temp->bitmask = $this->bitmask;
return $temp;
}
/**
* __toString() magic method
*
* Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
* toString().
*
* @access public
* @internal Implemented per a suggestion by Techie-Michael - thanks!
*/
function __toString()
{
return $this->toString();
}
/**
* __clone() magic method
*
* Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
* directly in PHP5. You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5
* only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5,
* call Math_BigInteger::copy(), instead.
*
* @access public
* @see self::copy()
* @return Math_BigInteger
*/
function __clone()
{
return $this->copy();
}
/**
* __sleep() magic method
*
* Will be called, automatically, when serialize() is called on a Math_BigInteger object.
*
* @see self::__wakeup()
* @access public
*/
function __sleep()
{
$this->hex = $this->toHex(true);
$vars = array('hex');
if ($this->precision > 0) {
$vars[] = 'precision';
}
return $vars;
}
/**
* __wakeup() magic method
*
* Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
*
* @see self::__sleep()
* @access public
*/
function __wakeup()
{
$temp = new Math_BigInteger($this->hex, -16);
$this->value = $temp->value;
$this->is_negative = $temp->is_negative;
if ($this->precision > 0) {
// recalculate $this->bitmask
$this->setPrecision($this->precision);
}
}
/**
* __debugInfo() magic method
*
* Will be called, automatically, when print_r() or var_dump() are called
*
* @access public
*/
function __debugInfo()
{
$opts = array();
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$engine = 'gmp';
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$engine = 'bcmath';
break;
case MATH_BIGINTEGER_MODE_INTERNAL:
$engine = 'internal';
$opts[] = PHP_INT_SIZE == 8 ? '64-bit' : '32-bit';
}
if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_GMP && defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
$opts[] = 'OpenSSL';
}
if (!empty($opts)) {
$engine.= ' (' . implode($opts, ', ') . ')';
}
return array(
'value' => '0x' . $this->toHex(true),
'engine' => $engine
);
}
/**
* Adds two BigIntegers.
*
* Here's an example:
*
* add($b);
*
* echo $c->toString(); // outputs 30
* ?>
*
*
* @param Math_BigInteger $y
* @return Math_BigInteger
* @access public
* @internal Performs base-2**52 addition
*/
function add($y)
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
$temp->value = gmp_add($this->value, $y->value);
return $this->_normalize($temp);
case MATH_BIGINTEGER_MODE_BCMATH:
$temp = new Math_BigInteger();
$temp->value = bcadd($this->value, $y->value, 0);
return $this->_normalize($temp);
}
$temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
$result = new Math_BigInteger();
$result->value = $temp[MATH_BIGINTEGER_VALUE];
$result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
return $this->_normalize($result);
}
/**
* Performs addition.
*
* @param array $x_value
* @param bool $x_negative
* @param array $y_value
* @param bool $y_negative
* @return array
* @access private
*/
function _add($x_value, $x_negative, $y_value, $y_negative)
{
$x_size = count($x_value);
$y_size = count($y_value);
if ($x_size == 0) {
return array(
MATH_BIGINTEGER_VALUE => $y_value,
MATH_BIGINTEGER_SIGN => $y_negative
);
} elseif ($y_size == 0) {
return array(
MATH_BIGINTEGER_VALUE => $x_value,
MATH_BIGINTEGER_SIGN => $x_negative
);
}
// subtract, if appropriate
if ($x_negative != $y_negative) {
if ($x_value == $y_value) {
return array(
MATH_BIGINTEGER_VALUE => array(),
MATH_BIGINTEGER_SIGN => false
);
}
$temp = $this->_subtract($x_value, false, $y_value, false);
$temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
$x_negative : $y_negative;
return $temp;
}
if ($x_size < $y_size) {
$size = $x_size;
$value = $y_value;
} else {
$size = $y_size;
$value = $x_value;
}
$value[count($value)] = 0; // just in case the carry adds an extra digit
$carry = 0;
for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
$sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry;
$carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
$sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
$temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
$value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
$value[$j] = $temp;
}
if ($j == $size) { // ie. if $y_size is odd
$sum = $x_value[$i] + $y_value[$i] + $carry;
$carry = $sum >= MATH_BIGINTEGER_BASE_FULL;
$value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;
++$i; // ie. let $i = $j since we've just done $value[$i]
}
if ($carry) {
for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) {
$value[$i] = 0;
}
++$value[$i];
}
return array(
MATH_BIGINTEGER_VALUE => $this->_trim($value),
MATH_BIGINTEGER_SIGN => $x_negative
);
}
/**
* Subtracts two BigIntegers.
*
* Here's an example:
*
* subtract($b);
*
* echo $c->toString(); // outputs -10
* ?>
*
*
* @param Math_BigInteger $y
* @return Math_BigInteger
* @access public
* @internal Performs base-2**52 subtraction
*/
function subtract($y)
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
$temp->value = gmp_sub($this->value, $y->value);
return $this->_normalize($temp);
case MATH_BIGINTEGER_MODE_BCMATH:
$temp = new Math_BigInteger();
$temp->value = bcsub($this->value, $y->value, 0);
return $this->_normalize($temp);
}
$temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
$result = new Math_BigInteger();
$result->value = $temp[MATH_BIGINTEGER_VALUE];
$result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
return $this->_normalize($result);
}
/**
* Performs subtraction.
*
* @param array $x_value
* @param bool $x_negative
* @param array $y_value
* @param bool $y_negative
* @return array
* @access private
*/
function _subtract($x_value, $x_negative, $y_value, $y_negative)
{
$x_size = count($x_value);
$y_size = count($y_value);
if ($x_size == 0) {
return array(
MATH_BIGINTEGER_VALUE => $y_value,
MATH_BIGINTEGER_SIGN => !$y_negative
);
} elseif ($y_size == 0) {
return array(
MATH_BIGINTEGER_VALUE => $x_value,
MATH_BIGINTEGER_SIGN => $x_negative
);
}
// add, if appropriate (ie. -$x - +$y or +$x - -$y)
if ($x_negative != $y_negative) {
$temp = $this->_add($x_value, false, $y_value, false);
$temp[MATH_BIGINTEGER_SIGN] = $x_negative;
return $temp;
}
$diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
if (!$diff) {
return array(
MATH_BIGINTEGER_VALUE => array(),
MATH_BIGINTEGER_SIGN => false
);
}
// switch $x and $y around, if appropriate.
if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) {
$temp = $x_value;
$x_value = $y_value;
$y_value = $temp;
$x_negative = !$x_negative;
$x_size = count($x_value);
$y_size = count($y_value);
}
// at this point, $x_value should be at least as big as - if not bigger than - $y_value
$carry = 0;
for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
$sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry;
$carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
$sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
$temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
$x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);
$x_value[$j] = $temp;
}
if ($j == $y_size) { // ie. if $y_size is odd
$sum = $x_value[$i] - $y_value[$i] - $carry;
$carry = $sum < 0;
$x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;
++$i;
}
if ($carry) {
for (; !$x_value[$i]; ++$i) {
$x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;
}
--$x_value[$i];
}
return array(
MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
MATH_BIGINTEGER_SIGN => $x_negative
);
}
/**
* Multiplies two BigIntegers
*
* Here's an example:
*
* multiply($b);
*
* echo $c->toString(); // outputs 200
* ?>
*
*
* @param Math_BigInteger $x
* @return Math_BigInteger
* @access public
*/
function multiply($x)
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
$temp->value = gmp_mul($this->value, $x->value);
return $this->_normalize($temp);
case MATH_BIGINTEGER_MODE_BCMATH:
$temp = new Math_BigInteger();
$temp->value = bcmul($this->value, $x->value, 0);
return $this->_normalize($temp);
}
$temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
$product = new Math_BigInteger();
$product->value = $temp[MATH_BIGINTEGER_VALUE];
$product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
return $this->_normalize($product);
}
/**
* Performs multiplication.
*
* @param array $x_value
* @param bool $x_negative
* @param array $y_value
* @param bool $y_negative
* @return array
* @access private
*/
function _multiply($x_value, $x_negative, $y_value, $y_negative)
{
//if ( $x_value == $y_value ) {
// return array(
// MATH_BIGINTEGER_VALUE => $this->_square($x_value),
// MATH_BIGINTEGER_SIGN => $x_sign != $y_value
// );
//}
$x_length = count($x_value);
$y_length = count($y_value);
if (!$x_length || !$y_length) { // a 0 is being multiplied
return array(
MATH_BIGINTEGER_VALUE => array(),
MATH_BIGINTEGER_SIGN => false
);
}
return array(
MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
$this->_trim($this->_regularMultiply($x_value, $y_value)) :
$this->_trim($this->_karatsuba($x_value, $y_value)),
MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
);
}
/**
* Performs long multiplication on two BigIntegers
*
* Modeled after 'multiply' in MutableBigInteger.java.
*
* @param array $x_value
* @param array $y_value
* @return array
* @access private
*/
function _regularMultiply($x_value, $y_value)
{
$x_length = count($x_value);
$y_length = count($y_value);
if (!$x_length || !$y_length) { // a 0 is being multiplied
return array();
}
if ($x_length < $y_length) {
$temp = $x_value;
$x_value = $y_value;
$y_value = $temp;
$x_length = count($x_value);
$y_length = count($y_value);
}
$product_value = $this->_array_repeat(0, $x_length + $y_length);
// the following for loop could be removed if the for loop following it
// (the one with nested for loops) initially set $i to 0, but
// doing so would also make the result in one set of unnecessary adds,
// since on the outermost loops first pass, $product->value[$k] is going
// to always be 0
$carry = 0;
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
$carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
}
$product_value[$j] = $carry;
// the above for loop is what the previous comment was talking about. the
// following for loop is the "one with nested for loops"
for ($i = 1; $i < $y_length; ++$i) {
$carry = 0;
for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
}
$product_value[$k] = $carry;
}
return $product_value;
}
/**
* Performs Karatsuba multiplication on two BigIntegers
*
* See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
*
* @param array $x_value
* @param array $y_value
* @return array
* @access private
*/
function _karatsuba($x_value, $y_value)
{
$m = min(count($x_value) >> 1, count($y_value) >> 1);
if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
return $this->_regularMultiply($x_value, $y_value);
}
$x1 = array_slice($x_value, $m);
$x0 = array_slice($x_value, 0, $m);
$y1 = array_slice($y_value, $m);
$y0 = array_slice($y_value, 0, $m);
$z2 = $this->_karatsuba($x1, $y1);
$z0 = $this->_karatsuba($x0, $y0);
$z1 = $this->_add($x1, false, $x0, false);
$temp = $this->_add($y1, false, $y0, false);
$z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
$temp = $this->_add($z2, false, $z0, false);
$z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
$z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
$z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
$xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
$xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
return $xy[MATH_BIGINTEGER_VALUE];
}
/**
* Performs squaring
*
* @param array $x
* @return array
* @access private
*/
function _square($x = false)
{
return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
$this->_trim($this->_baseSquare($x)) :
$this->_trim($this->_karatsubaSquare($x));
}
/**
* Performs traditional squaring on two BigIntegers
*
* Squaring can be done faster than multiplying a number by itself can be. See
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
*
* @param array $value
* @return array
* @access private
*/
function _baseSquare($value)
{
if (empty($value)) {
return array();
}
$square_value = $this->_array_repeat(0, 2 * count($value));
for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
$i2 = $i << 1;
$temp = $square_value[$i2] + $value[$i] * $value[$i];
$carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
// note how we start from $i+1 instead of 0 as we do in multiplication.
for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
$temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
$carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
}
// the following line can yield values larger 2**15. at this point, PHP should switch
// over to floats.
$square_value[$i + $max_index + 1] = $carry;
}
return $square_value;
}
/**
* Performs Karatsuba "squaring" on two BigIntegers
*
* See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
*
* @param array $value
* @return array
* @access private
*/
function _karatsubaSquare($value)
{
$m = count($value) >> 1;
if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
return $this->_baseSquare($value);
}
$x1 = array_slice($value, $m);
$x0 = array_slice($value, 0, $m);
$z2 = $this->_karatsubaSquare($x1);
$z0 = $this->_karatsubaSquare($x0);
$z1 = $this->_add($x1, false, $x0, false);
$z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
$temp = $this->_add($z2, false, $z0, false);
$z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
$z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
$z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
$xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
$xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
return $xx[MATH_BIGINTEGER_VALUE];
}
/**
* Divides two BigIntegers.
*
* Returns an array whose first element contains the quotient and whose second element contains the
* "common residue". If the remainder would be positive, the "common residue" and the remainder are the
* same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder
* and the divisor (basically, the "common residue" is the first positive modulo).
*
* Here's an example:
*
* divide($b);
*
* echo $quotient->toString(); // outputs 0
* echo "\r\n";
* echo $remainder->toString(); // outputs 10
* ?>
*
*
* @param Math_BigInteger $y
* @return array
* @access public
* @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
*/
function divide($y)
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$quotient = new Math_BigInteger();
$remainder = new Math_BigInteger();
list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
if (gmp_sign($remainder->value) < 0) {
$remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
}
return array($this->_normalize($quotient), $this->_normalize($remainder));
case MATH_BIGINTEGER_MODE_BCMATH:
$quotient = new Math_BigInteger();
$remainder = new Math_BigInteger();
$quotient->value = bcdiv($this->value, $y->value, 0);
$remainder->value = bcmod($this->value, $y->value);
if ($remainder->value[0] == '-') {
$remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
}
return array($this->_normalize($quotient), $this->_normalize($remainder));
}
if (count($y->value) == 1) {
list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
$quotient = new Math_BigInteger();
$remainder = new Math_BigInteger();
$quotient->value = $q;
$remainder->value = array($r);
$quotient->is_negative = $this->is_negative != $y->is_negative;
return array($this->_normalize($quotient), $this->_normalize($remainder));
}
static $zero;
if (!isset($zero)) {
$zero = new Math_BigInteger();
}
$x = $this->copy();
$y = $y->copy();
$x_sign = $x->is_negative;
$y_sign = $y->is_negative;
$x->is_negative = $y->is_negative = false;
$diff = $x->compare($y);
if (!$diff) {
$temp = new Math_BigInteger();
$temp->value = array(1);
$temp->is_negative = $x_sign != $y_sign;
return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));
}
if ($diff < 0) {
// if $x is negative, "add" $y.
if ($x_sign) {
$x = $y->subtract($x);
}
return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x));
}
// normalize $x and $y as described in HAC 14.23 / 14.24
$msb = $y->value[count($y->value) - 1];
for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) {
$msb <<= 1;
}
$x->_lshift($shift);
$y->_lshift($shift);
$y_value = &$y->value;
$x_max = count($x->value) - 1;
$y_max = count($y->value) - 1;
$quotient = new Math_BigInteger();
$quotient_value = &$quotient->value;
$quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
static $temp, $lhs, $rhs;
if (!isset($temp)) {
$temp = new Math_BigInteger();
$lhs = new Math_BigInteger();
$rhs = new Math_BigInteger();
}
$temp_value = &$temp->value;
$rhs_value = &$rhs->value;
// $temp = $y << ($x_max - $y_max-1) in base 2**26
$temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
while ($x->compare($temp) >= 0) {
// calculate the "common residue"
++$quotient_value[$x_max - $y_max];
$x = $x->subtract($temp);
$x_max = count($x->value) - 1;
}
for ($i = $x_max; $i >= $y_max + 1; --$i) {
$x_value = &$x->value;
$x_window = array(
isset($x_value[$i]) ? $x_value[$i] : 0,
isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
);
$y_window = array(
$y_value[$y_max],
($y_max > 0) ? $y_value[$y_max - 1] : 0
);
$q_index = $i - $y_max - 1;
if ($x_window[0] == $y_window[0]) {
$quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;
} else {
$quotient_value[$q_index] = $this->_safe_divide(
$x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1],
$y_window[0]
);
}
$temp_value = array($y_window[1], $y_window[0]);
$lhs->value = array($quotient_value[$q_index]);
$lhs = $lhs->multiply($temp);
$rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
while ($lhs->compare($rhs) > 0) {
--$quotient_value[$q_index];
$lhs->value = array($quotient_value[$q_index]);
$lhs = $lhs->multiply($temp);
}
$adjust = $this->_array_repeat(0, $q_index);
$temp_value = array($quotient_value[$q_index]);
$temp = $temp->multiply($y);
$temp_value = &$temp->value;
$temp_value = array_merge($adjust, $temp_value);
$x = $x->subtract($temp);
if ($x->compare($zero) < 0) {
$temp_value = array_merge($adjust, $y_value);
$x = $x->add($temp);
--$quotient_value[$q_index];
}
$x_max = count($x_value) - 1;
}
// unnormalize the remainder
$x->_rshift($shift);
$quotient->is_negative = $x_sign != $y_sign;
// calculate the "common residue", if appropriate
if ($x_sign) {
$y->_rshift($shift);
$x = $y->subtract($x);
}
return array($this->_normalize($quotient), $this->_normalize($x));
}
/**
* Divides a BigInteger by a regular integer
*
* abc / x = a00 / x + b0 / x + c / x
*
* @param array $dividend
* @param array $divisor
* @return array
* @access private
*/
function _divide_digit($dividend, $divisor)
{
$carry = 0;
$result = array();
for ($i = count($dividend) - 1; $i >= 0; --$i) {
$temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i];
$result[$i] = $this->_safe_divide($temp, $divisor);
$carry = (int) ($temp - $divisor * $result[$i]);
}
return array($result, $carry);
}
/**
* Performs modular exponentiation.
*
* Here's an example:
*
* modPow($b, $c);
*
* echo $c->toString(); // outputs 10
* ?>
*
*
* @param Math_BigInteger $e
* @param Math_BigInteger $n
* @return Math_BigInteger
* @access public
* @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
* and although the approach involving repeated squaring does vastly better, it, too, is impractical
* for our purposes. The reason being that division - by far the most complicated and time-consuming
* of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
*
* Modular reductions resolve this issue. Although an individual modular reduction takes more time
* then an individual division, when performed in succession (with the same modulo), they're a lot faster.
*
* The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction,
* although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the
* base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
* the product of two odd numbers is odd), but what about when RSA isn't used?
*
* In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a
* Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the
* modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however,
* uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
* the other, a power of two - and recombine them, later. This is the method that this modPow function uses.
* {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
*/
function modPow($e, $n)
{
$n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
if ($e->compare(new Math_BigInteger()) < 0) {
$e = $e->abs();
$temp = $this->modInverse($n);
if ($temp === false) {
return false;
}
return $this->_normalize($temp->modPow($e, $n));
}
if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP) {
$temp = new Math_BigInteger();
$temp->value = gmp_powm($this->value, $e->value, $n->value);
return $this->_normalize($temp);
}
if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) {
list(, $temp) = $this->divide($n);
return $temp->modPow($e, $n);
}
if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
$components = array(
'modulus' => $n->toBytes(true),
'publicExponent' => $e->toBytes(true)
);
$components = array(
'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
);
$RSAPublicKey = pack(
'Ca*a*a*',
48,
$this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
$components['modulus'],
$components['publicExponent']
);
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$RSAPublicKey = chr(0) . $RSAPublicKey;
$RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
$encapsulated = pack(
'Ca*a*',
48,
$this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)),
$rsaOID . $RSAPublicKey
);
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($encapsulated)) .
'-----END PUBLIC KEY-----';
$plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);
if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
return new Math_BigInteger($result, 256);
}
}
if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) {
$temp = new Math_BigInteger();
$temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
return $this->_normalize($temp);
}
if (empty($e->value)) {
$temp = new Math_BigInteger();
$temp->value = array(1);
return $this->_normalize($temp);
}
if ($e->value == array(1)) {
list(, $temp) = $this->divide($n);
return $this->_normalize($temp);
}
if ($e->value == array(2)) {
$temp = new Math_BigInteger();
$temp->value = $this->_square($this->value);
list(, $temp) = $temp->divide($n);
return $this->_normalize($temp);
}
return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));
// the following code, although not callable, can be run independently of the above code
// although the above code performed better in my benchmarks the following could might
// perform better under different circumstances. in lieu of deleting it it's just been
// made uncallable
// is the modulo odd?
if ($n->value[0] & 1) {
return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
}
// if it's not, it's even
// find the lowest set bit (eg. the max pow of 2 that divides $n)
for ($i = 0; $i < count($n->value); ++$i) {
if ($n->value[$i]) {
$temp = decbin($n->value[$i]);
$j = strlen($temp) - strrpos($temp, '1') - 1;
$j+= 26 * $i;
break;
}
}
// at this point, 2^$j * $n/(2^$j) == $n
$mod1 = $n->copy();
$mod1->_rshift($j);
$mod2 = new Math_BigInteger();
$mod2->value = array(1);
$mod2->_lshift($j);
$part1 = ($mod1->value != array(1)) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger();
$part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);
$y1 = $mod2->modInverse($mod1);
$y2 = $mod1->modInverse($mod2);
$result = $part1->multiply($mod2);
$result = $result->multiply($y1);
$temp = $part2->multiply($mod1);
$temp = $temp->multiply($y2);
$result = $result->add($temp);
list(, $result) = $result->divide($n);
return $this->_normalize($result);
}
/**
* Performs modular exponentiation.
*
* Alias for Math_BigInteger::modPow()
*
* @param Math_BigInteger $e
* @param Math_BigInteger $n
* @return Math_BigInteger
* @access public
*/
function powMod($e, $n)
{
return $this->modPow($e, $n);
}
/**
* Sliding Window k-ary Modular Exponentiation
*
* Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims,
* however, this function performs a modular reduction after every multiplication and squaring operation.
* As such, this function has the same preconditions that the reductions being used do.
*
* @param Math_BigInteger $e
* @param Math_BigInteger $n
* @param int $mode
* @return Math_BigInteger
* @access private
*/
function _slidingWindow($e, $n, $mode)
{
static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
//static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1
$e_value = $e->value;
$e_length = count($e_value) - 1;
$e_bits = decbin($e_value[$e_length]);
for ($i = $e_length - 1; $i >= 0; --$i) {
$e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT);
}
$e_length = strlen($e_bits);
// calculate the appropriate window size.
// $window_size == 3 if $window_ranges is between 25 and 81, for example.
for ($i = 0, $window_size = 1; $i < count($window_ranges) && $e_length > $window_ranges[$i]; ++$window_size, ++$i) {
}
$n_value = $n->value;
// precompute $this^0 through $this^$window_size
$powers = array();
$powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
$powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
// we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
// in a 1. ie. it's supposed to be odd.
$temp = 1 << ($window_size - 1);
for ($i = 1; $i < $temp; ++$i) {
$i2 = $i << 1;
$powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
}
$result = array(1);
$result = $this->_prepareReduce($result, $n_value, $mode);
for ($i = 0; $i < $e_length;) {
if (!$e_bits[$i]) {
$result = $this->_squareReduce($result, $n_value, $mode);
++$i;
} else {
for ($j = $window_size - 1; $j > 0; --$j) {
if (!empty($e_bits[$i + $j])) {
break;
}
}
// eg. the length of substr($e_bits, $i, $j + 1)
for ($k = 0; $k <= $j; ++$k) {
$result = $this->_squareReduce($result, $n_value, $mode);
}
$result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
$i += $j + 1;
}
}
$temp = new Math_BigInteger();
$temp->value = $this->_reduce($result, $n_value, $mode);
return $temp;
}
/**
* Modular reduction
*
* For most $modes this will return the remainder.
*
* @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
* @param int $mode
* @return array
*/
function _reduce($x, $n, $mode)
{
switch ($mode) {
case MATH_BIGINTEGER_MONTGOMERY:
return $this->_montgomery($x, $n);
case MATH_BIGINTEGER_BARRETT:
return $this->_barrett($x, $n);
case MATH_BIGINTEGER_POWEROF2:
$lhs = new Math_BigInteger();
$lhs->value = $x;
$rhs = new Math_BigInteger();
$rhs->value = $n;
return $x->_mod2($n);
case MATH_BIGINTEGER_CLASSIC:
$lhs = new Math_BigInteger();
$lhs->value = $x;
$rhs = new Math_BigInteger();
$rhs->value = $n;
list(, $temp) = $lhs->divide($rhs);
return $temp->value;
case MATH_BIGINTEGER_NONE:
return $x;
default:
// an invalid $mode was provided
}
}
/**
* Modular reduction preperation
*
* @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
* @param int $mode
* @return array
*/
function _prepareReduce($x, $n, $mode)
{
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
return $this->_prepMontgomery($x, $n);
}
return $this->_reduce($x, $n, $mode);
}
/**
* Modular multiply
*
* @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $y
* @param array $n
* @param int $mode
* @return array
*/
function _multiplyReduce($x, $y, $n, $mode)
{
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
return $this->_montgomeryMultiply($x, $y, $n);
}
$temp = $this->_multiply($x, false, $y, false);
return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);
}
/**
* Modular square
*
* @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
* @param int $mode
* @return array
*/
function _squareReduce($x, $n, $mode)
{
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
return $this->_montgomeryMultiply($x, $x, $n);
}
return $this->_reduce($this->_square($x), $n, $mode);
}
/**
* Modulos for Powers of Two
*
* Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1),
* we'll just use this function as a wrapper for doing that.
*
* @see self::_slidingWindow()
* @access private
* @param Math_BigInteger
* @return Math_BigInteger
*/
function _mod2($n)
{
$temp = new Math_BigInteger();
$temp->value = array(1);
return $this->bitwise_and($n->subtract($temp));
}
/**
* Barrett Modular Reduction
*
* See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly,
* so as not to require negative numbers (initially, this script didn't support negative numbers).
*
* Employs "folding", as described at
* {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from
* it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
*
* Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
* usable on account of (1) its not using reasonable radix points as discussed in
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
* radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that
* (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line
* comments for details.
*
* @see self::_slidingWindow()
* @access private
* @param array $n
* @param array $m
* @return array
*/
function _barrett($n, $m)
{
static $cache = array(
MATH_BIGINTEGER_VARIABLE => array(),
MATH_BIGINTEGER_DATA => array()
);
$m_length = count($m);
// if ($this->_compare($n, $this->_square($m)) >= 0) {
if (count($n) > 2 * $m_length) {
$lhs = new Math_BigInteger();
$rhs = new Math_BigInteger();
$lhs->value = $n;
$rhs->value = $m;
list(, $temp) = $lhs->divide($rhs);
return $temp->value;
}
// if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
if ($m_length < 5) {
return $this->_regularBarrett($n, $m);
}
// n = 2 * m.length
if (($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false) {
$key = count($cache[MATH_BIGINTEGER_VARIABLE]);
$cache[MATH_BIGINTEGER_VARIABLE][] = $m;
$lhs = new Math_BigInteger();
$lhs_value = &$lhs->value;
$lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
$lhs_value[] = 1;
$rhs = new Math_BigInteger();
$rhs->value = $m;
list($u, $m1) = $lhs->divide($rhs);
$u = $u->value;
$m1 = $m1->value;
$cache[MATH_BIGINTEGER_DATA][] = array(
'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
'm1'=> $m1 // m.length
);
} else {
extract($cache[MATH_BIGINTEGER_DATA][$key]);
}
$cutoff = $m_length + ($m_length >> 1);
$lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
$msd = array_slice($n, $cutoff); // m.length >> 1
$lsd = $this->_trim($lsd);
$temp = $this->_multiply($msd, false, $m1, false);
$n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1
if ($m_length & 1) {
return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);
}
// (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
$temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1);
// if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
// if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
$temp = $this->_multiply($temp, false, $u, false);
// if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
// if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
$temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1);
// if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
// if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1)
$temp = $this->_multiply($temp, false, $m, false);
// at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
// number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop
// following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
$result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {
$result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);
}
return $result[MATH_BIGINTEGER_VALUE];
}
/**
* (Regular) Barrett Modular Reduction
*
* For numbers with more than four digits Math_BigInteger::_barrett() is faster. The difference between that and this
* is that this function does not fold the denominator into a smaller form.
*
* @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
* @return array
*/
function _regularBarrett($x, $n)
{
static $cache = array(
MATH_BIGINTEGER_VARIABLE => array(),
MATH_BIGINTEGER_DATA => array()
);
$n_length = count($n);
if (count($x) > 2 * $n_length) {
$lhs = new Math_BigInteger();
$rhs = new Math_BigInteger();
$lhs->value = $x;
$rhs->value = $n;
list(, $temp) = $lhs->divide($rhs);
return $temp->value;
}
if (($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false) {
$key = count($cache[MATH_BIGINTEGER_VARIABLE]);
$cache[MATH_BIGINTEGER_VARIABLE][] = $n;
$lhs = new Math_BigInteger();
$lhs_value = &$lhs->value;
$lhs_value = $this->_array_repeat(0, 2 * $n_length);
$lhs_value[] = 1;
$rhs = new Math_BigInteger();
$rhs->value = $n;
list($temp, ) = $lhs->divide($rhs); // m.length
$cache[MATH_BIGINTEGER_DATA][] = $temp->value;
}
// 2 * m.length - (m.length - 1) = m.length + 1
$temp = array_slice($x, $n_length - 1);
// (m.length + 1) + m.length = 2 * m.length + 1
$temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);
// (2 * m.length + 1) - (m.length - 1) = m.length + 2
$temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1);
// m.length + 1
$result = array_slice($x, 0, $n_length + 1);
// m.length + 1
$temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
// $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)
if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
$corrector_value = $this->_array_repeat(0, $n_length + 1);
$corrector_value[count($corrector_value)] = 1;
$result = $this->_add($result, false, $corrector_value, false);
$result = $result[MATH_BIGINTEGER_VALUE];
}
// at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
$result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);
while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {
$result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false);
}
return $result[MATH_BIGINTEGER_VALUE];
}
/**
* Performs long multiplication up to $stop digits
*
* If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
*
* @see self::_regularBarrett()
* @param array $x_value
* @param bool $x_negative
* @param array $y_value
* @param bool $y_negative
* @param int $stop
* @return array
* @access private
*/
function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
{
$x_length = count($x_value);
$y_length = count($y_value);
if (!$x_length || !$y_length) { // a 0 is being multiplied
return array(
MATH_BIGINTEGER_VALUE => array(),
MATH_BIGINTEGER_SIGN => false
);
}
if ($x_length < $y_length) {
$temp = $x_value;
$x_value = $y_value;
$y_value = $temp;
$x_length = count($x_value);
$y_length = count($y_value);
}
$product_value = $this->_array_repeat(0, $x_length + $y_length);
// the following for loop could be removed if the for loop following it
// (the one with nested for loops) initially set $i to 0, but
// doing so would also make the result in one set of unnecessary adds,
// since on the outermost loops first pass, $product->value[$k] is going
// to always be 0
$carry = 0;
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
$carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
}
if ($j < $stop) {
$product_value[$j] = $carry;
}
// the above for loop is what the previous comment was talking about. the
// following for loop is the "one with nested for loops"
for ($i = 1; $i < $y_length; ++$i) {
$carry = 0;
for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
$carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
}
if ($k < $stop) {
$product_value[$k] = $carry;
}
}
return array(
MATH_BIGINTEGER_VALUE => $this->_trim($product_value),
MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
);
}
/**
* Montgomery Modular Reduction
*
* ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
* improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function
* to work correctly.
*
* @see self::_prepMontgomery()
* @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
* @return array
*/
function _montgomery($x, $n)
{
static $cache = array(
MATH_BIGINTEGER_VARIABLE => array(),
MATH_BIGINTEGER_DATA => array()
);
if (($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false) {
$key = count($cache[MATH_BIGINTEGER_VARIABLE]);
$cache[MATH_BIGINTEGER_VARIABLE][] = $x;
$cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n);
}
$k = count($n);
$result = array(MATH_BIGINTEGER_VALUE => $x);
for ($i = 0; $i < $k; ++$i) {
$temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
$temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
$temp = $this->_regularMultiply(array($temp), $n);
$temp = array_merge($this->_array_repeat(0, $i), $temp);
$result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
}
$result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k);
if ($this->_compare($result, false, $n, false) >= 0) {
$result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);
}
return $result[MATH_BIGINTEGER_VALUE];
}
/**
* Montgomery Multiply
*
* Interleaves the montgomery reduction and long multiplication algorithms together as described in
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
*
* @see self::_prepMontgomery()
* @see self::_montgomery()
* @access private
* @param array $x
* @param array $y
* @param array $m
* @return array
*/
function _montgomeryMultiply($x, $y, $m)
{
$temp = $this->_multiply($x, false, $y, false);
return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);
// the following code, although not callable, can be run independently of the above code
// although the above code performed better in my benchmarks the following could might
// perform better under different circumstances. in lieu of deleting it it's just been
// made uncallable
static $cache = array(
MATH_BIGINTEGER_VARIABLE => array(),
MATH_BIGINTEGER_DATA => array()
);
if (($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false) {
$key = count($cache[MATH_BIGINTEGER_VARIABLE]);
$cache[MATH_BIGINTEGER_VARIABLE][] = $m;
$cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m);
}
$n = max(count($x), count($y), count($m));
$x = array_pad($x, $n, 0);
$y = array_pad($y, $n, 0);
$m = array_pad($m, $n, 0);
$a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
for ($i = 0; $i < $n; ++$i) {
$temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
$temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
$temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
$temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
$temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
$a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
$a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
}
if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {
$a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);
}
return $a[MATH_BIGINTEGER_VALUE];
}
/**
* Prepare a number for use in Montgomery Modular Reductions
*
* @see self::_montgomery()
* @see self::_slidingWindow()
* @access private
* @param array $x
* @param array $n
* @return array
*/
function _prepMontgomery($x, $n)
{
$lhs = new Math_BigInteger();
$lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
$rhs = new Math_BigInteger();
$rhs->value = $n;
list(, $temp) = $lhs->divide($rhs);
return $temp->value;
}
/**
* Modular Inverse of a number mod 2**26 (eg. 67108864)
*
* Based off of the bnpInvDigit function implemented and justified in the following URL:
*
* {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
*
* The following URL provides more info:
*
* {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
*
* As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For
* instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
* int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
* auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
* the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
* maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to
* 40 bits, which only 64-bit floating points will support.
*
* Thanks to Pedro Gimeno Fortea for input!
*
* @see self::_montgomery()
* @access private
* @param array $x
* @return int
*/
function _modInverse67108864($x) // 2**26 == 67,108,864
{
$x = -$x[0];
$result = $x & 0x3; // x**-1 mod 2**2
$result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
$result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
$result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
$result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26
return $result & MATH_BIGINTEGER_MAX_DIGIT;
}
/**
* Calculates modular inverses.
*
* Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
*
* Here's an example:
*
* modInverse($b);
* echo $c->toString(); // outputs 4
*
* echo "\r\n";
*
* $d = $a->multiply($c);
* list(, $d) = $d->divide($b);
* echo $d; // outputs 1 (as per the definition of modular inverse)
* ?>
*
*
* @param Math_BigInteger $n
* @return Math_BigInteger|false
* @access public
* @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
*/
function modInverse($n)
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
$temp->value = gmp_invert($this->value, $n->value);
return ($temp->value === false) ? false : $this->_normalize($temp);
}
static $zero, $one;
if (!isset($zero)) {
$zero = new Math_BigInteger();
$one = new Math_BigInteger(1);
}
// $x mod -$n == $x mod $n.
$n = $n->abs();
if ($this->compare($zero) < 0) {
$temp = $this->abs();
$temp = $temp->modInverse($n);
return $this->_normalize($n->subtract($temp));
}
extract($this->extendedGCD($n));
if (!$gcd->equals($one)) {
return false;
}
$x = $x->compare($zero) < 0 ? $x->add($n) : $x;
return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
}
/**
* Calculates the greatest common divisor and Bezout's identity.
*
* Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that
* 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which
* combination is returned is dependent upon which mode is in use. See
* {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
*
* Here's an example:
*
* extendedGCD($b));
*
* echo $gcd->toString() . "\r\n"; // outputs 21
* echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
* ?>
*
*
* @param Math_BigInteger $n
* @return Math_BigInteger
* @access public
* @internal Calculates the GCD using the binary xGCD algorithim described in
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes,
* the more traditional algorithim requires "relatively costly multiple-precision divisions".
*/
function extendedGCD($n)
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
extract(gmp_gcdext($this->value, $n->value));
return array(
'gcd' => $this->_normalize(new Math_BigInteger($g)),
'x' => $this->_normalize(new Math_BigInteger($s)),
'y' => $this->_normalize(new Math_BigInteger($t))
);
case MATH_BIGINTEGER_MODE_BCMATH:
// it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
// best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is,
// the basic extended euclidean algorithim is what we're using.
$u = $this->value;
$v = $n->value;
$a = '1';
$b = '0';
$c = '0';
$d = '1';
while (bccomp($v, '0', 0) != 0) {
$q = bcdiv($u, $v, 0);
$temp = $u;
$u = $v;
$v = bcsub($temp, bcmul($v, $q, 0), 0);
$temp = $a;
$a = $c;
$c = bcsub($temp, bcmul($a, $q, 0), 0);
$temp = $b;
$b = $d;
$d = bcsub($temp, bcmul($b, $q, 0), 0);
}
return array(
'gcd' => $this->_normalize(new Math_BigInteger($u)),
'x' => $this->_normalize(new Math_BigInteger($a)),
'y' => $this->_normalize(new Math_BigInteger($b))
);
}
$y = $n->copy();
$x = $this->copy();
$g = new Math_BigInteger();
$g->value = array(1);
while (!(($x->value[0] & 1)|| ($y->value[0] & 1))) {
$x->_rshift(1);
$y->_rshift(1);
$g->_lshift(1);
}
$u = $x->copy();
$v = $y->copy();
$a = new Math_BigInteger();
$b = new Math_BigInteger();
$c = new Math_BigInteger();
$d = new Math_BigInteger();
$a->value = $d->value = $g->value = array(1);
$b->value = $c->value = array();
while (!empty($u->value)) {
while (!($u->value[0] & 1)) {
$u->_rshift(1);
if ((!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1))) {
$a = $a->add($y);
$b = $b->subtract($x);
}
$a->_rshift(1);
$b->_rshift(1);
}
while (!($v->value[0] & 1)) {
$v->_rshift(1);
if ((!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1))) {
$c = $c->add($y);
$d = $d->subtract($x);
}
$c->_rshift(1);
$d->_rshift(1);
}
if ($u->compare($v) >= 0) {
$u = $u->subtract($v);
$a = $a->subtract($c);
$b = $b->subtract($d);
} else {
$v = $v->subtract($u);
$c = $c->subtract($a);
$d = $d->subtract($b);
}
}
return array(
'gcd' => $this->_normalize($g->multiply($v)),
'x' => $this->_normalize($c),
'y' => $this->_normalize($d)
);
}
/**
* Calculates the greatest common divisor
*
* Say you have 693 and 609. The GCD is 21.
*
* Here's an example:
*
* extendedGCD($b);
*
* echo $gcd->toString() . "\r\n"; // outputs 21
* ?>
*
*
* @param Math_BigInteger $n
* @return Math_BigInteger
* @access public
*/
function gcd($n)
{
extract($this->extendedGCD($n));
return $gcd;
}
/**
* Absolute value.
*
* @return Math_BigInteger
* @access public
*/
function abs()
{
$temp = new Math_BigInteger();
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$temp->value = gmp_abs($this->value);
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
break;
default:
$temp->value = $this->value;
}
return $temp;
}
/**
* Compares two numbers.
*
* Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is
* demonstrated thusly:
*
* $x > $y: $x->compare($y) > 0
* $x < $y: $x->compare($y) < 0
* $x == $y: $x->compare($y) == 0
*
* Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
*
* @param Math_BigInteger $y
* @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
* @access public
* @see self::equals()
* @internal Could return $this->subtract($x), but that's not as fast as what we do do.
*/
function compare($y)
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
return gmp_cmp($this->value, $y->value);
case MATH_BIGINTEGER_MODE_BCMATH:
return bccomp($this->value, $y->value, 0);
}
return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
}
/**
* Compares two numbers.
*
* @param array $x_value
* @param bool $x_negative
* @param array $y_value
* @param bool $y_negative
* @return int
* @see self::compare()
* @access private
*/
function _compare($x_value, $x_negative, $y_value, $y_negative)
{
if ($x_negative != $y_negative) {
return (!$x_negative && $y_negative) ? 1 : -1;
}
$result = $x_negative ? -1 : 1;
if (count($x_value) != count($y_value)) {
return (count($x_value) > count($y_value)) ? $result : -$result;
}
$size = max(count($x_value), count($y_value));
$x_value = array_pad($x_value, $size, 0);
$y_value = array_pad($y_value, $size, 0);
for ($i = count($x_value) - 1; $i >= 0; --$i) {
if ($x_value[$i] != $y_value[$i]) {
return ($x_value[$i] > $y_value[$i]) ? $result : -$result;
}
}
return 0;
}
/**
* Tests the equality of two numbers.
*
* If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare()
*
* @param Math_BigInteger $x
* @return bool
* @access public
* @see self::compare()
*/
function equals($x)
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
return gmp_cmp($this->value, $x->value) == 0;
default:
return $this->value === $x->value && $this->is_negative == $x->is_negative;
}
}
/**
* Set Precision
*
* Some bitwise operations give different results depending on the precision being used. Examples include left
* shift, not, and rotates.
*
* @param int $bits
* @access public
*/
function setPrecision($bits)
{
$this->precision = $bits;
if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH) {
$this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
} else {
$this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0));
}
$temp = $this->_normalize($this);
$this->value = $temp->value;
}
/**
* Logical And
*
* @param Math_BigInteger $x
* @access public
* @internal Implemented per a request by Lluis Pamies i Juarez
* @return Math_BigInteger
*/
function bitwise_and($x)
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
$temp->value = gmp_and($this->value, $x->value);
return $this->_normalize($temp);
case MATH_BIGINTEGER_MODE_BCMATH:
$left = $this->toBytes();
$right = $x->toBytes();
$length = max(strlen($left), strlen($right));
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
return $this->_normalize(new Math_BigInteger($left & $right, 256));
}
$result = $this->copy();
$length = min(count($x->value), count($this->value));
$result->value = array_slice($result->value, 0, $length);
for ($i = 0; $i < $length; ++$i) {
$result->value[$i]&= $x->value[$i];
}
return $this->_normalize($result);
}
/**
* Logical Or
*
* @param Math_BigInteger $x
* @access public
* @internal Implemented per a request by Lluis Pamies i Juarez
* @return Math_BigInteger
*/
function bitwise_or($x)
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
$temp->value = gmp_or($this->value, $x->value);
return $this->_normalize($temp);
case MATH_BIGINTEGER_MODE_BCMATH:
$left = $this->toBytes();
$right = $x->toBytes();
$length = max(strlen($left), strlen($right));
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
return $this->_normalize(new Math_BigInteger($left | $right, 256));
}
$length = max(count($this->value), count($x->value));
$result = $this->copy();
$result->value = array_pad($result->value, $length, 0);
$x->value = array_pad($x->value, $length, 0);
for ($i = 0; $i < $length; ++$i) {
$result->value[$i]|= $x->value[$i];
}
return $this->_normalize($result);
}
/**
* Logical Exclusive-Or
*
* @param Math_BigInteger $x
* @access public
* @internal Implemented per a request by Lluis Pamies i Juarez
* @return Math_BigInteger
*/
function bitwise_xor($x)
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
$temp = new Math_BigInteger();
$temp->value = gmp_xor(gmp_abs($this->value), gmp_abs($x->value));
return $this->_normalize($temp);
case MATH_BIGINTEGER_MODE_BCMATH:
$left = $this->toBytes();
$right = $x->toBytes();
$length = max(strlen($left), strlen($right));
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
return $this->_normalize(new Math_BigInteger($left ^ $right, 256));
}
$length = max(count($this->value), count($x->value));
$result = $this->copy();
$result->is_negative = false;
$result->value = array_pad($result->value, $length, 0);
$x->value = array_pad($x->value, $length, 0);
for ($i = 0; $i < $length; ++$i) {
$result->value[$i]^= $x->value[$i];
}
return $this->_normalize($result);
}
/**
* Logical Not
*
* @access public
* @internal Implemented per a request by Lluis Pamies i Juarez
* @return Math_BigInteger
*/
function bitwise_not()
{
// calculuate "not" without regard to $this->precision
// (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0)
$temp = $this->toBytes();
if ($temp == '') {
return $this->_normalize(new Math_BigInteger());
}
$pre_msb = decbin(ord($temp[0]));
$temp = ~$temp;
$msb = decbin(ord($temp[0]));
if (strlen($msb) == 8) {
$msb = substr($msb, strpos($msb, '0'));
}
$temp[0] = chr(bindec($msb));
// see if we need to add extra leading 1's
$current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
$new_bits = $this->precision - $current_bits;
if ($new_bits <= 0) {
return $this->_normalize(new Math_BigInteger($temp, 256));
}
// generate as many leading 1's as we need to.
$leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
$this->_base256_lshift($leading_ones, $current_bits);
$temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);
return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));
}
/**
* Logical Right Shift
*
* Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
*
* @param int $shift
* @return Math_BigInteger
* @access public
* @internal The only version that yields any speed increases is the internal version.
*/
function bitwise_rightShift($shift)
{
$temp = new Math_BigInteger();
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
static $two;
if (!isset($two)) {
$two = gmp_init('2');
}
$temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
break;
default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
// and I don't want to do that...
$temp->value = $this->value;
$temp->_rshift($shift);
}
return $this->_normalize($temp);
}
/**
* Logical Left Shift
*
* Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
*
* @param int $shift
* @return Math_BigInteger
* @access public
* @internal The only version that yields any speed increases is the internal version.
*/
function bitwise_leftShift($shift)
{
$temp = new Math_BigInteger();
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
static $two;
if (!isset($two)) {
$two = gmp_init('2');
}
$temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
break;
case MATH_BIGINTEGER_MODE_BCMATH:
$temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
break;
default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
// and I don't want to do that...
$temp->value = $this->value;
$temp->_lshift($shift);
}
return $this->_normalize($temp);
}
/**
* Logical Left Rotate
*
* Instead of the top x bits being dropped they're appended to the shifted bit string.
*
* @param int $shift
* @return Math_BigInteger
* @access public
*/
function bitwise_leftRotate($shift)
{
$bits = $this->toBytes();
if ($this->precision > 0) {
$precision = $this->precision;
if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) {
$mask = $this->bitmask->subtract(new Math_BigInteger(1));
$mask = $mask->toBytes();
} else {
$mask = $this->bitmask->toBytes();
}
} else {
$temp = ord($bits[0]);
for ($i = 0; $temp >> $i; ++$i) {
}
$precision = 8 * strlen($bits) - 8 + $i;
$mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
}
if ($shift < 0) {
$shift+= $precision;
}
$shift%= $precision;
if (!$shift) {
return $this->copy();
}
$left = $this->bitwise_leftShift($shift);
$left = $left->bitwise_and(new Math_BigInteger($mask, 256));
$right = $this->bitwise_rightShift($precision - $shift);
$result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
return $this->_normalize($result);
}
/**
* Logical Right Rotate
*
* Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
*
* @param int $shift
* @return Math_BigInteger
* @access public
*/
function bitwise_rightRotate($shift)
{
return $this->bitwise_leftRotate(-$shift);
}
/**
* Set random number generator function
*
* This function is deprecated.
*
* @param string $generator
* @access public
*/
function setRandomGenerator($generator)
{
}
/**
* Generates a random BigInteger
*
* Byte length is equal to $length. Uses crypt_random if it's loaded and mt_rand if it's not.
*
* @param int $length
* @return Math_BigInteger
* @access private
*/
function _random_number_helper($size)
{
if (function_exists('crypt_random_string')) {
$random = crypt_random_string($size);
} else {
$random = '';
if ($size & 1) {
$random.= chr(mt_rand(0, 255));
}
$blocks = $size >> 1;
for ($i = 0; $i < $blocks; ++$i) {
// mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
$random.= pack('n', mt_rand(0, 0xFFFF));
}
}
return new Math_BigInteger($random, 256);
}
/**
* Generate a random number
*
* Returns a random number between $min and $max where $min and $max
* can be defined using one of the two methods:
*
* $min->random($max)
* $max->random($min)
*
* @param Math_BigInteger $arg1
* @param Math_BigInteger $arg2
* @return Math_BigInteger
* @access public
* @internal The API for creating random numbers used to be $a->random($min, $max), where $a was a Math_BigInteger object.
* That method is still supported for BC purposes.
*/
function random($arg1, $arg2 = false)
{
if ($arg1 === false) {
return false;
}
if ($arg2 === false) {
$max = $arg1;
$min = $this;
} else {
$min = $arg1;
$max = $arg2;
}
$compare = $max->compare($min);
if (!$compare) {
return $this->_normalize($min);
} elseif ($compare < 0) {
// if $min is bigger then $max, swap $min and $max
$temp = $max;
$max = $min;
$min = $temp;
}
static $one;
if (!isset($one)) {
$one = new Math_BigInteger(1);
}
$max = $max->subtract($min->subtract($one));
$size = strlen(ltrim($max->toBytes(), chr(0)));
/*
doing $random % $max doesn't work because some numbers will be more likely to occur than others.
eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145
would produce 5 whereas the only value of random that could produce 139 would be 139. ie.
not all numbers would be equally likely. some would be more likely than others.
creating a whole new random number until you find one that is within the range doesn't work
because, for sufficiently small ranges, the likelihood that you'd get a number within that range
would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability
would be pretty high that $random would be greater than $max.
phpseclib works around this using the technique described here:
http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
*/
$random_max = new Math_BigInteger(chr(1) . str_repeat("\0", $size), 256);
$random = $this->_random_number_helper($size);
list($max_multiple) = $random_max->divide($max);
$max_multiple = $max_multiple->multiply($max);
while ($random->compare($max_multiple) >= 0) {
$random = $random->subtract($max_multiple);
$random_max = $random_max->subtract($max_multiple);
$random = $random->bitwise_leftShift(8);
$random = $random->add($this->_random_number_helper(1));
$random_max = $random_max->bitwise_leftShift(8);
list($max_multiple) = $random_max->divide($max);
$max_multiple = $max_multiple->multiply($max);
}
list(, $random) = $random->divide($max);
return $this->_normalize($random->add($min));
}
/**
* Generate a random prime number.
*
* If there's not a prime within the given range, false will be returned.
* If more than $timeout seconds have elapsed, give up and return false.
*
* @param Math_BigInteger $arg1
* @param Math_BigInteger $arg2
* @param int $timeout
* @return Math_BigInteger|false
* @access public
* @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
*/
function randomPrime($arg1, $arg2 = false, $timeout = false)
{
if ($arg1 === false) {
return false;
}
if ($arg2 === false) {
$max = $arg1;
$min = $this;
} else {
$min = $arg1;
$max = $arg2;
}
$compare = $max->compare($min);
if (!$compare) {
return $min->isPrime() ? $min : false;
} elseif ($compare < 0) {
// if $min is bigger then $max, swap $min and $max
$temp = $max;
$max = $min;
$min = $temp;
}
static $one, $two;
if (!isset($one)) {
$one = new Math_BigInteger(1);
$two = new Math_BigInteger(2);
}
$start = time();
$x = $this->random($min, $max);
// gmp_nextprime() requires PHP 5 >= 5.2.0 per .
if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && extension_loaded('gmp') && version_compare(PHP_VERSION, '5.2.0', '>=')) {
$p = new Math_BigInteger();
$p->value = gmp_nextprime($x->value);
if ($p->compare($max) <= 0) {
return $p;
}
if (!$min->equals($x)) {
$x = $x->subtract($one);
}
return $x->randomPrime($min, $x);
}
if ($x->equals($two)) {
return $x;
}
$x->_make_odd();
if ($x->compare($max) > 0) {
// if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
if ($min->equals($max)) {
return false;
}
$x = $min->copy();
$x->_make_odd();
}
$initial_x = $x->copy();
while (true) {
if ($timeout !== false && time() - $start > $timeout) {
return false;
}
if ($x->isPrime()) {
return $x;
}
$x = $x->add($two);
if ($x->compare($max) > 0) {
$x = $min->copy();
if ($x->equals($two)) {
return $x;
}
$x->_make_odd();
}
if ($x->equals($initial_x)) {
return false;
}
}
}
/**
* Make the current number odd
*
* If the current number is odd it'll be unchanged. If it's even, one will be added to it.
*
* @see self::randomPrime()
* @access private
*/
function _make_odd()
{
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
gmp_setbit($this->value, 0);
break;
case MATH_BIGINTEGER_MODE_BCMATH:
if ($this->value[strlen($this->value) - 1] % 2 == 0) {
$this->value = bcadd($this->value, '1');
}
break;
default:
$this->value[0] |= 1;
}
}
/**
* Checks a numer to see if it's prime
*
* Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the
* $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed across multiple pageloads
* on a website instead of just one.
*
* @param Math_BigInteger $t
* @return bool
* @access public
* @internal Uses the
* {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
*/
function isPrime($t = false)
{
$length = strlen($this->toBytes());
if (!$t) {
// see HAC 4.49 "Note (controlling the error probability)"
// @codingStandardsIgnoreStart
if ($length >= 163) { $t = 2; } // floor(1300 / 8)
else if ($length >= 106) { $t = 3; } // floor( 850 / 8)
else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8)
else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8)
else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8)
else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8)
else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8)
else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8)
else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
else { $t = 27; }
// @codingStandardsIgnoreEnd
}
// ie. gmp_testbit($this, 0)
// ie. isEven() or !isOdd()
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
return gmp_prob_prime($this->value, $t) != 0;
case MATH_BIGINTEGER_MODE_BCMATH:
if ($this->value === '2') {
return true;
}
if ($this->value[strlen($this->value) - 1] % 2 == 0) {
return false;
}
break;
default:
if ($this->value == array(2)) {
return true;
}
if (~$this->value[0] & 1) {
return false;
}
}
static $primes, $zero, $one, $two;
if (!isset($primes)) {
$primes = array(
3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
953, 967, 971, 977, 983, 991, 997
);
if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
for ($i = 0; $i < count($primes); ++$i) {
$primes[$i] = new Math_BigInteger($primes[$i]);
}
}
$zero = new Math_BigInteger();
$one = new Math_BigInteger(1);
$two = new Math_BigInteger(2);
}
if ($this->equals($one)) {
return false;
}
// see HAC 4.4.1 "Random search for probable primes"
if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
foreach ($primes as $prime) {
list(, $r) = $this->divide($prime);
if ($r->equals($zero)) {
return $this->equals($prime);
}
}
} else {
$value = $this->value;
foreach ($primes as $prime) {
list(, $r) = $this->_divide_digit($value, $prime);
if (!$r) {
return count($value) == 1 && $value[0] == $prime;
}
}
}
$n = $this->copy();
$n_1 = $n->subtract($one);
$n_2 = $n->subtract($two);
$r = $n_1->copy();
$r_value = $r->value;
// ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) {
$s = 0;
// if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
while ($r->value[strlen($r->value) - 1] % 2 == 0) {
$r->value = bcdiv($r->value, '2', 0);
++$s;
}
} else {
for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
$temp = ~$r_value[$i] & 0xFFFFFF;
for ($j = 1; ($temp >> $j) & 1; ++$j) {
}
if ($j != 25) {
break;
}
}
$s = 26 * $i + $j;
$r->_rshift($s);
}
for ($i = 0; $i < $t; ++$i) {
$a = $this->random($two, $n_2);
$y = $a->modPow($r, $n);
if (!$y->equals($one) && !$y->equals($n_1)) {
for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
$y = $y->modPow($two, $n);
if ($y->equals($one)) {
return false;
}
}
if (!$y->equals($n_1)) {
return false;
}
}
}
return true;
}
/**
* Logical Left Shift
*
* Shifts BigInteger's by $shift bits.
*
* @param int $shift
* @access private
*/
function _lshift($shift)
{
if ($shift == 0) {
return;
}
$num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
$shift %= MATH_BIGINTEGER_BASE;
$shift = 1 << $shift;
$carry = 0;
for ($i = 0; $i < count($this->value); ++$i) {
$temp = $this->value[$i] * $shift + $carry;
$carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
$this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL);
}
if ($carry) {
$this->value[count($this->value)] = $carry;
}
while ($num_digits--) {
array_unshift($this->value, 0);
}
}
/**
* Logical Right Shift
*
* Shifts BigInteger's by $shift bits.
*
* @param int $shift
* @access private
*/
function _rshift($shift)
{
if ($shift == 0) {
return;
}
$num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
$shift %= MATH_BIGINTEGER_BASE;
$carry_shift = MATH_BIGINTEGER_BASE - $shift;
$carry_mask = (1 << $shift) - 1;
if ($num_digits) {
$this->value = array_slice($this->value, $num_digits);
}
$carry = 0;
for ($i = count($this->value) - 1; $i >= 0; --$i) {
$temp = $this->value[$i] >> $shift | $carry;
$carry = ($this->value[$i] & $carry_mask) << $carry_shift;
$this->value[$i] = $temp;
}
$this->value = $this->_trim($this->value);
}
/**
* Normalize
*
* Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
*
* @param Math_BigInteger
* @return Math_BigInteger
* @see self::_trim()
* @access private
*/
function _normalize($result)
{
$result->precision = $this->precision;
$result->bitmask = $this->bitmask;
switch (MATH_BIGINTEGER_MODE) {
case MATH_BIGINTEGER_MODE_GMP:
if ($this->bitmask !== false) {
$result->value = gmp_and($result->value, $result->bitmask->value);
}
return $result;
case MATH_BIGINTEGER_MODE_BCMATH:
if (!empty($result->bitmask->value)) {
$result->value = bcmod($result->value, $result->bitmask->value);
}
return $result;
}
$value = &$result->value;
if (!count($value)) {
return $result;
}
$value = $this->_trim($value);
if (!empty($result->bitmask->value)) {
$length = min(count($value), count($this->bitmask->value));
$value = array_slice($value, 0, $length);
for ($i = 0; $i < $length; ++$i) {
$value[$i] = $value[$i] & $this->bitmask->value[$i];
}
}
return $result;
}
/**
* Trim
*
* Removes leading zeros
*
* @param array $value
* @return Math_BigInteger
* @access private
*/
function _trim($value)
{
for ($i = count($value) - 1; $i >= 0; --$i) {
if ($value[$i]) {
break;
}
unset($value[$i]);
}
return $value;
}
/**
* Array Repeat
*
* @param $input Array
* @param $multiplier mixed
* @return array
* @access private
*/
function _array_repeat($input, $multiplier)
{
return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
}
/**
* Logical Left Shift
*
* Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
*
* @param $x String
* @param $shift Integer
* @return string
* @access private
*/
function _base256_lshift(&$x, $shift)
{
if ($shift == 0) {
return;
}
$num_bytes = $shift >> 3; // eg. floor($shift/8)
$shift &= 7; // eg. $shift % 8
$carry = 0;
for ($i = strlen($x) - 1; $i >= 0; --$i) {
$temp = ord($x[$i]) << $shift | $carry;
$x[$i] = chr($temp);
$carry = $temp >> 8;
}
$carry = ($carry != 0) ? chr($carry) : '';
$x = $carry . $x . str_repeat(chr(0), $num_bytes);
}
/**
* Logical Right Shift
*
* Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
*
* @param $x String
* @param $shift Integer
* @return string
* @access private
*/
function _base256_rshift(&$x, $shift)
{
if ($shift == 0) {
$x = ltrim($x, chr(0));
return '';
}
$num_bytes = $shift >> 3; // eg. floor($shift/8)
$shift &= 7; // eg. $shift % 8
$remainder = '';
if ($num_bytes) {
$start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
$remainder = substr($x, $start);
$x = substr($x, 0, -$num_bytes);
}
$carry = 0;
$carry_shift = 8 - $shift;
for ($i = 0; $i < strlen($x); ++$i) {
$temp = (ord($x[$i]) >> $shift) | $carry;
$carry = (ord($x[$i]) << $carry_shift) & 0xFF;
$x[$i] = chr($temp);
}
$x = ltrim($x, chr(0));
$remainder = chr($carry >> $carry_shift) . $remainder;
return ltrim($remainder, chr(0));
}
// one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
// at 32-bits, while java's longs are 64-bits.
/**
* Converts 32-bit integers to bytes.
*
* @param int $x
* @return string
* @access private
*/
function _int2bytes($x)
{
return ltrim(pack('N', $x), chr(0));
}
/**
* Converts bytes to 32-bit integers
*
* @param string $x
* @return int
* @access private
*/
function _bytes2int($x)
{
$temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
return $temp['int'];
}
/**
* DER-encode an integer
*
* The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
*
* @see self::modPow()
* @access private
* @param int $length
* @return string
*/
function _encodeASN1Length($length)
{
if ($length <= 0x7F) {
return chr($length);
}
$temp = ltrim(pack('N', $length), chr(0));
return pack('Ca*', 0x80 | strlen($temp), $temp);
}
/**
* Single digit division
*
* Even if int64 is being used the division operator will return a float64 value
* if the dividend is not evenly divisible by the divisor. Since a float64 doesn't
* have the precision of int64 this is a problem so, when int64 is being used,
* we'll guarantee that the dividend is divisible by first subtracting the remainder.
*
* @access private
* @param int $x
* @param int $y
* @return int
*/
function _safe_divide($x, $y)
{
if (MATH_BIGINTEGER_BASE === 26) {
return (int) ($x / $y);
}
// MATH_BIGINTEGER_BASE === 31
return ($x - ($x % $y)) / $y;
}
}
================================================
FILE: assets/libraries/phpseclib/Net/SCP.php
================================================
* login('username', 'password')) {
* exit('bad login');
* }
*
* $scp = new Net_SCP($ssh);
* $scp->put('abcd', str_repeat('x', 1024*1024));
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Net
* @package Net_SCP
* @author Jim Wigginton
* @copyright 2010 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**#@+
* @access public
* @see self::put()
*/
/**
* Reads data from a local file.
*/
define('NET_SCP_LOCAL_FILE', 1);
/**
* Reads data from a string.
*/
define('NET_SCP_STRING', 2);
/**#@-*/
/**#@+
* @access private
* @see self::_send()
* @see self::_receive()
*/
/**
* SSH1 is being used.
*/
define('NET_SCP_SSH1', 1);
/**
* SSH2 is being used.
*/
define('NET_SCP_SSH2', 2);
/**#@-*/
/**
* Pure-PHP implementations of SCP.
*
* @package Net_SCP
* @author Jim Wigginton
* @access public
*/
class Net_SCP
{
/**
* SSH Object
*
* @var object
* @access private
*/
var $ssh;
/**
* Packet Size
*
* @var int
* @access private
*/
var $packet_size;
/**
* Mode
*
* @var int
* @access private
*/
var $mode;
/**
* Default Constructor.
*
* Connects to an SSH server
*
* @param Net_SSH1|Net_SSH2 $ssh
* @return Net_SCP
* @access public
*/
function __construct($ssh)
{
if (!is_object($ssh)) {
return;
}
switch (strtolower(get_class($ssh))) {
case 'net_ssh2':
$this->mode = NET_SCP_SSH2;
break;
case 'net_ssh1':
$this->packet_size = 50000;
$this->mode = NET_SCP_SSH1;
break;
default:
return;
}
$this->ssh = $ssh;
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param Net_SSH1|Net_SSH2 $ssh
* @access public
*/
function Net_SCP($ssh)
{
$this->__construct($ssh);
}
/**
* Uploads a file to the SCP server.
*
* By default, Net_SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
* So, for example, if you set $data to 'filename.ext' and then do Net_SCP::get(), you will get a file, twelve bytes
* long, containing 'filename.ext' as its contents.
*
* Setting $mode to NET_SCP_LOCAL_FILE will change the above behavior. With NET_SCP_LOCAL_FILE, $remote_file will
* contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
* large $remote_file will be, as well.
*
* Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
* care of that, yourself.
*
* @param string $remote_file
* @param string $data
* @param int $mode
* @param callable $callback
* @return bool
* @access public
*/
function put($remote_file, $data, $mode = NET_SCP_STRING, $callback = null)
{
if (!isset($this->ssh)) {
return false;
}
if (empty($remote_file)) {
user_error('remote_file cannot be blank', E_USER_NOTICE);
return false;
}
if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
return false;
}
$temp = $this->_receive();
if ($temp !== chr(0)) {
return false;
}
if ($this->mode == NET_SCP_SSH2) {
$this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC] - 4;
}
$remote_file = basename($remote_file);
if ($mode == NET_SCP_STRING) {
$size = strlen($data);
} else {
if (!is_file($data)) {
user_error("$data is not a valid file", E_USER_NOTICE);
return false;
}
$fp = @fopen($data, 'rb');
if (!$fp) {
return false;
}
$size = filesize($data);
}
$this->_send('C0644 ' . $size . ' ' . $remote_file . "\n");
$temp = $this->_receive();
if ($temp !== chr(0)) {
return false;
}
$sent = 0;
while ($sent < $size) {
$temp = $mode & NET_SCP_STRING ? substr($data, $sent, $this->packet_size) : fread($fp, $this->packet_size);
$this->_send($temp);
$sent+= strlen($temp);
if (is_callable($callback)) {
call_user_func($callback, $sent);
}
}
$this->_close();
if ($mode != NET_SCP_STRING) {
fclose($fp);
}
return true;
}
/**
* Downloads a file from the SCP server.
*
* Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
* the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
* operation
*
* @param string $remote_file
* @param string $local_file
* @return mixed
* @access public
*/
function get($remote_file, $local_file = false)
{
if (!isset($this->ssh)) {
return false;
}
if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from
return false;
}
$this->_send("\0");
if (!preg_match('#(?[^ ]+) (?\d+) (?.+)#', rtrim($this->_receive()), $info)) {
return false;
}
$this->_send("\0");
$size = 0;
if ($local_file !== false) {
$fp = @fopen($local_file, 'wb');
if (!$fp) {
return false;
}
}
$content = '';
while ($size < $info['size']) {
$data = $this->_receive();
// SCP usually seems to split stuff out into 16k chunks
$size+= strlen($data);
if ($local_file === false) {
$content.= $data;
} else {
fputs($fp, $data);
}
}
$this->_close();
if ($local_file !== false) {
fclose($fp);
return true;
}
return $content;
}
/**
* Sends a packet to an SSH server
*
* @param string $data
* @access private
*/
function _send($data)
{
switch ($this->mode) {
case NET_SCP_SSH2:
$this->ssh->_send_channel_packet(NET_SSH2_CHANNEL_EXEC, $data);
break;
case NET_SCP_SSH1:
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data);
$this->ssh->_send_binary_packet($data);
}
}
/**
* Receives a packet from an SSH server
*
* @return string
* @access private
*/
function _receive()
{
switch ($this->mode) {
case NET_SCP_SSH2:
return $this->ssh->_get_channel_packet(NET_SSH2_CHANNEL_EXEC, true);
case NET_SCP_SSH1:
if (!$this->ssh->bitmap) {
return false;
}
while (true) {
$response = $this->ssh->_get_binary_packet();
switch ($response[NET_SSH1_RESPONSE_TYPE]) {
case NET_SSH1_SMSG_STDOUT_DATA:
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nlength', $response[NET_SSH1_RESPONSE_DATA]));
return $this->ssh->_string_shift($response[NET_SSH1_RESPONSE_DATA], $length);
case NET_SSH1_SMSG_STDERR_DATA:
break;
case NET_SSH1_SMSG_EXITSTATUS:
$this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION));
fclose($this->ssh->fsock);
$this->ssh->bitmap = 0;
return false;
default:
user_error('Unknown packet received', E_USER_NOTICE);
return false;
}
}
}
}
/**
* Closes the connection to an SSH server
*
* @access private
*/
function _close()
{
switch ($this->mode) {
case NET_SCP_SSH2:
$this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC, true);
break;
case NET_SCP_SSH1:
$this->ssh->disconnect();
}
}
}
================================================
FILE: assets/libraries/phpseclib/Net/SFTP/Stream.php
================================================
* @copyright 2013 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* SFTP Stream Wrapper
*
* @package Net_SFTP_Stream
* @author Jim Wigginton
* @access public
*/
class Net_SFTP_Stream
{
/**
* SFTP instances
*
* Rather than re-create the connection we re-use instances if possible
*
* @var array
*/
static $instances;
/**
* SFTP instance
*
* @var object
* @access private
*/
var $sftp;
/**
* Path
*
* @var string
* @access private
*/
var $path;
/**
* Mode
*
* @var string
* @access private
*/
var $mode;
/**
* Position
*
* @var int
* @access private
*/
var $pos;
/**
* Size
*
* @var int
* @access private
*/
var $size;
/**
* Directory entries
*
* @var array
* @access private
*/
var $entries;
/**
* EOF flag
*
* @var bool
* @access private
*/
var $eof;
/**
* Context resource
*
* Technically this needs to be publically accessible so PHP can set it directly
*
* @var resource
* @access public
*/
var $context;
/**
* Notification callback function
*
* @var callable
* @access public
*/
var $notification;
/**
* Registers this class as a URL wrapper.
*
* @param string $protocol The wrapper name to be registered.
* @return bool True on success, false otherwise.
* @access public
*/
static function register($protocol = 'sftp')
{
if (in_array($protocol, stream_get_wrappers(), true)) {
return false;
}
$class = function_exists('get_called_class') ? get_called_class() : __CLASS__;
return stream_wrapper_register($protocol, $class);
}
/**
* The Constructor
*
* @access public
*/
function __construct()
{
if (defined('NET_SFTP_STREAM_LOGGING')) {
echo "__construct()\r\n";
}
if (!class_exists('Net_SFTP')) {
include_once 'Net/SFTP.php';
}
}
/**
* Path Parser
*
* Extract a path from a URI and actually connect to an SSH server if appropriate
*
* If "notification" is set as a context parameter the message code for successful login is
* NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE.
*
* @param string $path
* @return string
* @access private
*/
function _parse_path($path)
{
$orig = $path;
extract(parse_url($path) + array('port' => 22));
if (isset($query)) {
$path.= '?' . $query;
} elseif (preg_match('/(\?|\?#)$/', $orig)) {
$path.= '?';
}
if (isset($fragment)) {
$path.= '#' . $fragment;
} elseif ($orig[strlen($orig) - 1] == '#') {
$path.= '#';
}
if (!isset($host)) {
return false;
}
if (isset($this->context)) {
$context = stream_context_get_params($this->context);
if (isset($context['notification'])) {
$this->notification = $context['notification'];
}
}
if ($host[0] == '$') {
$host = substr($host, 1);
global ${$host};
if (!is_object($$host) || get_class($$host) != 'Net_SFTP') {
return false;
}
$this->sftp = $$host;
} else {
if (isset($this->context)) {
$context = stream_context_get_options($this->context);
}
if (isset($context[$scheme]['session'])) {
$sftp = $context[$scheme]['session'];
}
if (isset($context[$scheme]['sftp'])) {
$sftp = $context[$scheme]['sftp'];
}
if (isset($sftp) && is_object($sftp) && get_class($sftp) == 'Net_SFTP') {
$this->sftp = $sftp;
return $path;
}
if (isset($context[$scheme]['username'])) {
$user = $context[$scheme]['username'];
}
if (isset($context[$scheme]['password'])) {
$pass = $context[$scheme]['password'];
}
if (isset($context[$scheme]['privkey']) && is_object($context[$scheme]['privkey']) && get_Class($context[$scheme]['privkey']) == 'Crypt_RSA') {
$pass = $context[$scheme]['privkey'];
}
if (!isset($user) || !isset($pass)) {
return false;
}
// casting $pass to a string is necessary in the event that it's a Crypt_RSA object
if (isset(self::$instances[$host][$port][$user][(string) $pass])) {
$this->sftp = self::$instances[$host][$port][$user][(string) $pass];
} else {
$this->sftp = new Net_SFTP($host, $port);
$this->sftp->disableStatCache();
if (isset($this->notification) && is_callable($this->notification)) {
/* if !is_callable($this->notification) we could do this:
user_error('fopen(): failed to call user notifier', E_USER_WARNING);
the ftp wrapper gives errors like that when the notifier isn't callable.
i've opted not to do that, however, since the ftp wrapper gives the line
on which the fopen occurred as the line number - not the line that the
user_error is on.
*/
call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
if (!$this->sftp->login($user, $pass)) {
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0);
return false;
}
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0);
} else {
if (!$this->sftp->login($user, $pass)) {
return false;
}
}
self::$instances[$host][$port][$user][(string) $pass] = $this->sftp;
}
}
return $path;
}
/**
* Opens file or URL
*
* @param string $path
* @param string $mode
* @param int $options
* @param string $opened_path
* @return bool
* @access public
*/
function _stream_open($path, $mode, $options, &$opened_path)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
$this->path = $path;
$this->size = $this->sftp->size($path);
$this->mode = preg_replace('#[bt]$#', '', $mode);
$this->eof = false;
if ($this->size === false) {
if ($this->mode[0] == 'r') {
return false;
} else {
$this->sftp->touch($path);
$this->size = 0;
}
} else {
switch ($this->mode[0]) {
case 'x':
return false;
case 'w':
$this->sftp->truncate($path, 0);
$this->size = 0;
}
}
$this->pos = $this->mode[0] != 'a' ? 0 : $this->size;
return true;
}
/**
* Read from stream
*
* @param int $count
* @return mixed
* @access public
*/
function _stream_read($count)
{
switch ($this->mode) {
case 'w':
case 'a':
case 'x':
case 'c':
return false;
}
// commented out because some files - eg. /dev/urandom - will say their size is 0 when in fact it's kinda infinite
//if ($this->pos >= $this->size) {
// $this->eof = true;
// return false;
//}
$result = $this->sftp->get($this->path, false, $this->pos, $count);
if (isset($this->notification) && is_callable($this->notification)) {
if ($result === false) {
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
return 0;
}
// seems that PHP calls stream_read in 8k chunks
call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $this->size);
}
if (empty($result)) { // ie. false or empty string
$this->eof = true;
return false;
}
$this->pos+= strlen($result);
return $result;
}
/**
* Write to stream
*
* @param string $data
* @return mixed
* @access public
*/
function _stream_write($data)
{
switch ($this->mode) {
case 'r':
return false;
}
$result = $this->sftp->put($this->path, $data, NET_SFTP_STRING, $this->pos);
if (isset($this->notification) && is_callable($this->notification)) {
if (!$result) {
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
return 0;
}
// seems that PHP splits up strings into 8k blocks before calling stream_write
call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data));
}
if ($result === false) {
return false;
}
$this->pos+= strlen($data);
if ($this->pos > $this->size) {
$this->size = $this->pos;
}
$this->eof = false;
return strlen($data);
}
/**
* Retrieve the current position of a stream
*
* @return int
* @access public
*/
function _stream_tell()
{
return $this->pos;
}
/**
* Tests for end-of-file on a file pointer
*
* In my testing there are four classes functions that normally effect the pointer:
* fseek, fputs / fwrite, fgets / fread and ftruncate.
*
* Only fgets / fread, however, results in feof() returning true. do fputs($fp, 'aaa') on a blank file and feof()
* will return false. do fread($fp, 1) and feof() will then return true. do fseek($fp, 10) on ablank file and feof()
* will return false. do fread($fp, 1) and feof() will then return true.
*
* @return bool
* @access public
*/
function _stream_eof()
{
return $this->eof;
}
/**
* Seeks to specific location in a stream
*
* @param int $offset
* @param int $whence
* @return bool
* @access public
*/
function _stream_seek($offset, $whence)
{
switch ($whence) {
case SEEK_SET:
if ($offset >= $this->size || $offset < 0) {
return false;
}
break;
case SEEK_CUR:
$offset+= $this->pos;
break;
case SEEK_END:
$offset+= $this->size;
}
$this->pos = $offset;
$this->eof = false;
return true;
}
/**
* Change stream options
*
* @param string $path
* @param int $option
* @param mixed $var
* @return bool
* @access public
*/
function _stream_metadata($path, $option, $var)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
// stream_metadata was introduced in PHP 5.4.0 but as of 5.4.11 the constants haven't been defined
// see http://www.php.net/streamwrapper.stream-metadata and https://bugs.php.net/64246
// and https://github.com/php/php-src/blob/master/main/php_streams.h#L592
switch ($option) {
case 1: // PHP_STREAM_META_TOUCH
return $this->sftp->touch($path, $var[0], $var[1]);
case 2: // PHP_STREAM_OWNER_NAME
case 3: // PHP_STREAM_GROUP_NAME
return false;
case 4: // PHP_STREAM_META_OWNER
return $this->sftp->chown($path, $var);
case 5: // PHP_STREAM_META_GROUP
return $this->sftp->chgrp($path, $var);
case 6: // PHP_STREAM_META_ACCESS
return $this->sftp->chmod($path, $var) !== false;
}
}
/**
* Retrieve the underlaying resource
*
* @param int $cast_as
* @return resource
* @access public
*/
function _stream_cast($cast_as)
{
return $this->sftp->fsock;
}
/**
* Advisory file locking
*
* @param int $operation
* @return bool
* @access public
*/
function _stream_lock($operation)
{
return false;
}
/**
* Renames a file or directory
*
* Attempts to rename oldname to newname, moving it between directories if necessary.
* If newname exists, it will be overwritten. This is a departure from what Net_SFTP
* does.
*
* @param string $path_from
* @param string $path_to
* @return bool
* @access public
*/
function _rename($path_from, $path_to)
{
$path1 = parse_url($path_from);
$path2 = parse_url($path_to);
unset($path1['path'], $path2['path']);
if ($path1 != $path2) {
return false;
}
$path_from = $this->_parse_path($path_from);
$path_to = parse_url($path_to);
if ($path_from === false) {
return false;
}
$path_to = $path_to['path']; // the $component part of parse_url() was added in PHP 5.1.2
// "It is an error if there already exists a file with the name specified by newpath."
// -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5
if (!$this->sftp->rename($path_from, $path_to)) {
if ($this->sftp->stat($path_to)) {
return $this->sftp->delete($path_to, true) && $this->sftp->rename($path_from, $path_to);
}
return false;
}
return true;
}
/**
* Open directory handle
*
* The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and
* removed in 5.4 I'm just going to ignore it.
*
* Also, nlist() is the best that this function is realistically going to be able to do. When an SFTP client
* sends a SSH_FXP_READDIR packet you don't generally get info on just one file but on multiple files. Quoting
* the SFTP specs:
*
* The SSH_FXP_NAME response has the following format:
*
* uint32 id
* uint32 count
* repeats count times:
* string filename
* string longname
* ATTRS attrs
*
* @param string $path
* @param int $options
* @return bool
* @access public
*/
function _dir_opendir($path, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
$this->pos = 0;
$this->entries = $this->sftp->nlist($path);
return $this->entries !== false;
}
/**
* Read entry from directory handle
*
* @return mixed
* @access public
*/
function _dir_readdir()
{
if (isset($this->entries[$this->pos])) {
return $this->entries[$this->pos++];
}
return false;
}
/**
* Rewind directory handle
*
* @return bool
* @access public
*/
function _dir_rewinddir()
{
$this->pos = 0;
return true;
}
/**
* Close directory handle
*
* @return bool
* @access public
*/
function _dir_closedir()
{
return true;
}
/**
* Create a directory
*
* Only valid $options is STREAM_MKDIR_RECURSIVE
*
* @param string $path
* @param int $mode
* @param int $options
* @return bool
* @access public
*/
function _mkdir($path, $mode, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
return $this->sftp->mkdir($path, $mode, $options & STREAM_MKDIR_RECURSIVE);
}
/**
* Removes a directory
*
* Only valid $options is STREAM_MKDIR_RECURSIVE per , however,
* does not have a $recursive parameter as mkdir() does so I don't know how
* STREAM_MKDIR_RECURSIVE is supposed to be set. Also, when I try it out with rmdir() I get 8 as
* $options. What does 8 correspond to?
*
* @param string $path
* @param int $mode
* @param int $options
* @return bool
* @access public
*/
function _rmdir($path, $options)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
return $this->sftp->rmdir($path);
}
/**
* Flushes the output
*
* See . Always returns true because Net_SFTP doesn't cache stuff before writing
*
* @return bool
* @access public
*/
function _stream_flush()
{
return true;
}
/**
* Retrieve information about a file resource
*
* @return mixed
* @access public
*/
function _stream_stat()
{
$results = $this->sftp->stat($this->path);
if ($results === false) {
return false;
}
return $results;
}
/**
* Delete a file
*
* @param string $path
* @return bool
* @access public
*/
function _unlink($path)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
return $this->sftp->delete($path, false);
}
/**
* Retrieve information about a file
*
* Ignores the STREAM_URL_STAT_QUIET flag because the entirety of Net_SFTP_Stream is quiet by default
* might be worthwhile to reconstruct bits 12-16 (ie. the file type) if mode doesn't have them but we'll
* cross that bridge when and if it's reached
*
* @param string $path
* @param int $flags
* @return mixed
* @access public
*/
function _url_stat($path, $flags)
{
$path = $this->_parse_path($path);
if ($path === false) {
return false;
}
$results = $flags & STREAM_URL_STAT_LINK ? $this->sftp->lstat($path) : $this->sftp->stat($path);
if ($results === false) {
return false;
}
return $results;
}
/**
* Truncate stream
*
* @param int $new_size
* @return bool
* @access public
*/
function _stream_truncate($new_size)
{
if (!$this->sftp->truncate($this->path, $new_size)) {
return false;
}
$this->eof = false;
$this->size = $new_size;
return true;
}
/**
* Change stream options
*
* STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush isn't.
* The other two aren't supported because of limitations in Net_SFTP.
*
* @param int $option
* @param int $arg1
* @param int $arg2
* @return bool
* @access public
*/
function _stream_set_option($option, $arg1, $arg2)
{
return false;
}
/**
* Close an resource
*
* @access public
*/
function _stream_close()
{
}
/**
* __call Magic Method
*
* When you're utilizing an SFTP stream you're not calling the methods in this class directly - PHP is calling them for you.
* Which kinda begs the question... what methods is PHP calling and what parameters is it passing to them? This function
* lets you figure that out.
*
* If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not
* NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method.
*
* @param string
* @param array
* @return mixed
* @access public
*/
function __call($name, $arguments)
{
if (defined('NET_SFTP_STREAM_LOGGING')) {
echo $name . '(';
$last = count($arguments) - 1;
foreach ($arguments as $i => $argument) {
var_export($argument);
if ($i != $last) {
echo ',';
}
}
echo ")\r\n";
}
$name = '_' . $name;
if (!method_exists($this, $name)) {
return false;
}
return call_user_func_array(array($this, $name), $arguments);
}
}
Net_SFTP_Stream::register();
================================================
FILE: assets/libraries/phpseclib/Net/SFTP.php
================================================
* login('username', 'password')) {
* exit('Login Failed');
* }
*
* echo $sftp->pwd() . "\r\n";
* $sftp->put('filename.ext', 'hello, world!');
* print_r($sftp->nlist());
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Net
* @package Net_SFTP
* @author Jim Wigginton
* @copyright 2009 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Net_SSH2
*/
if (!class_exists('Net_SSH2')) {
include_once 'SSH2.php';
}
/**#@+
* @access public
* @see self::getLog()
*/
/**
* Returns the message numbers
*/
define('NET_SFTP_LOG_SIMPLE', NET_SSH2_LOG_SIMPLE);
/**
* Returns the message content
*/
define('NET_SFTP_LOG_COMPLEX', NET_SSH2_LOG_COMPLEX);
/**
* Outputs the message content in real-time.
*/
define('NET_SFTP_LOG_REALTIME', 3);
/**#@-*/
/**
* SFTP channel constant
*
* Net_SSH2::exec() uses 0 and Net_SSH2::read() / Net_SSH2::write() use 1.
*
* @see Net_SSH2::_send_channel_packet()
* @see Net_SSH2::_get_channel_packet()
* @access private
*/
define('NET_SFTP_CHANNEL', 0x100);
/**#@+
* @access public
* @see self::put()
*/
/**
* Reads data from a local file.
*/
define('NET_SFTP_LOCAL_FILE', 1);
/**
* Reads data from a string.
*/
// this value isn't really used anymore but i'm keeping it reserved for historical reasons
define('NET_SFTP_STRING', 2);
/**
* Reads data from callback:
* function callback($length) returns string to proceed, null for EOF
*/
define('NET_SFTP_CALLBACK', 16);
/**
* Resumes an upload
*/
define('NET_SFTP_RESUME', 4);
/**
* Append a local file to an already existing remote file
*/
define('NET_SFTP_RESUME_START', 8);
/**#@-*/
/**
* Pure-PHP implementations of SFTP.
*
* @package Net_SFTP
* @author Jim Wigginton
* @access public
*/
class Net_SFTP extends Net_SSH2
{
/**
* Packet Types
*
* @see self::Net_SFTP()
* @var array
* @access private
*/
var $packet_types = array();
/**
* Status Codes
*
* @see self::Net_SFTP()
* @var array
* @access private
*/
var $status_codes = array();
/**
* The Request ID
*
* The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
* concurrent actions, so it's somewhat academic, here.
*
* @var boolean
* @see self::_send_sftp_packet()
* @access private
*/
var $use_request_id = false;
/**
* The Packet Type
*
* The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
* concurrent actions, so it's somewhat academic, here.
*
* @var int
* @see self::_get_sftp_packet()
* @access private
*/
var $packet_type = -1;
/**
* Packet Buffer
*
* @var string
* @see self::_get_sftp_packet()
* @access private
*/
var $packet_buffer = '';
/**
* Extensions supported by the server
*
* @var array
* @see self::_initChannel()
* @access private
*/
var $extensions = array();
/**
* Server SFTP version
*
* @var int
* @see self::_initChannel()
* @access private
*/
var $version;
/**
* Current working directory
*
* @var string
* @see self::realpath()
* @see self::chdir()
* @access private
*/
var $pwd = false;
/**
* Packet Type Log
*
* @see self::getLog()
* @var array
* @access private
*/
var $packet_type_log = array();
/**
* Packet Log
*
* @see self::getLog()
* @var array
* @access private
*/
var $packet_log = array();
/**
* Error information
*
* @see self::getSFTPErrors()
* @see self::getLastSFTPError()
* @var array
* @access private
*/
var $sftp_errors = array();
/**
* Stat Cache
*
* Rather than always having to open a directory and close it immediately there after to see if a file is a directory
* we'll cache the results.
*
* @see self::_update_stat_cache()
* @see self::_remove_from_stat_cache()
* @see self::_query_stat_cache()
* @var array
* @access private
*/
var $stat_cache = array();
/**
* Max SFTP Packet Size
*
* @see self::Net_SFTP()
* @see self::get()
* @var array
* @access private
*/
var $max_sftp_packet;
/**
* Stat Cache Flag
*
* @see self::disableStatCache()
* @see self::enableStatCache()
* @var bool
* @access private
*/
var $use_stat_cache = true;
/**
* Sort Options
*
* @see self::_comparator()
* @see self::setListOrder()
* @var array
* @access private
*/
var $sortOptions = array();
/**
* Canonicalization Flag
*
* Determines whether or not paths should be canonicalized before being
* passed on to the remote server.
*
* @see self::enablePathCanonicalization()
* @see self::disablePathCanonicalization()
* @see self::realpath()
* @var bool
* @access private
*/
var $canonicalize_paths = true;
/**
* Request Buffers
*
* @see self::_get_sftp_packet()
* @var array
* @access private
*/
var $requestBuffer = array();
/**
* Default Constructor.
*
* Connects to an SFTP server
*
* @param string $host
* @param int $port
* @param int $timeout
* @return Net_SFTP
* @access public
*/
function __construct($host, $port = 22, $timeout = 10)
{
parent::__construct($host, $port, $timeout);
$this->max_sftp_packet = 1 << 15;
$this->packet_types = array(
1 => 'NET_SFTP_INIT',
2 => 'NET_SFTP_VERSION',
/* the format of SSH_FXP_OPEN changed between SFTPv4 and SFTPv5+:
SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.1
pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 */
3 => 'NET_SFTP_OPEN',
4 => 'NET_SFTP_CLOSE',
5 => 'NET_SFTP_READ',
6 => 'NET_SFTP_WRITE',
7 => 'NET_SFTP_LSTAT',
9 => 'NET_SFTP_SETSTAT',
11 => 'NET_SFTP_OPENDIR',
12 => 'NET_SFTP_READDIR',
13 => 'NET_SFTP_REMOVE',
14 => 'NET_SFTP_MKDIR',
15 => 'NET_SFTP_RMDIR',
16 => 'NET_SFTP_REALPATH',
17 => 'NET_SFTP_STAT',
/* the format of SSH_FXP_RENAME changed between SFTPv4 and SFTPv5+:
SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */
18 => 'NET_SFTP_RENAME',
19 => 'NET_SFTP_READLINK',
20 => 'NET_SFTP_SYMLINK',
101=> 'NET_SFTP_STATUS',
102=> 'NET_SFTP_HANDLE',
/* the format of SSH_FXP_NAME changed between SFTPv3 and SFTPv4+:
SFTPv4+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4
pre-SFTPv4 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 */
103=> 'NET_SFTP_DATA',
104=> 'NET_SFTP_NAME',
105=> 'NET_SFTP_ATTRS',
200=> 'NET_SFTP_EXTENDED'
);
$this->status_codes = array(
0 => 'NET_SFTP_STATUS_OK',
1 => 'NET_SFTP_STATUS_EOF',
2 => 'NET_SFTP_STATUS_NO_SUCH_FILE',
3 => 'NET_SFTP_STATUS_PERMISSION_DENIED',
4 => 'NET_SFTP_STATUS_FAILURE',
5 => 'NET_SFTP_STATUS_BAD_MESSAGE',
6 => 'NET_SFTP_STATUS_NO_CONNECTION',
7 => 'NET_SFTP_STATUS_CONNECTION_LOST',
8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED',
9 => 'NET_SFTP_STATUS_INVALID_HANDLE',
10 => 'NET_SFTP_STATUS_NO_SUCH_PATH',
11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS',
12 => 'NET_SFTP_STATUS_WRITE_PROTECT',
13 => 'NET_SFTP_STATUS_NO_MEDIA',
14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM',
15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED',
16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL',
17 => 'NET_SFTP_STATUS_LOCK_CONFLICT',
18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY',
19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY',
20 => 'NET_SFTP_STATUS_INVALID_FILENAME',
21 => 'NET_SFTP_STATUS_LINK_LOOP',
22 => 'NET_SFTP_STATUS_CANNOT_DELETE',
23 => 'NET_SFTP_STATUS_INVALID_PARAMETER',
24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY',
25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT',
26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED',
27 => 'NET_SFTP_STATUS_DELETE_PENDING',
28 => 'NET_SFTP_STATUS_FILE_CORRUPT',
29 => 'NET_SFTP_STATUS_OWNER_INVALID',
30 => 'NET_SFTP_STATUS_GROUP_INVALID',
31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK'
);
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1
// the order, in this case, matters quite a lot - see Net_SFTP::_parseAttributes() to understand why
$this->attributes = array(
0x00000001 => 'NET_SFTP_ATTR_SIZE',
0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+
0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
// 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers
// yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
// two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
// that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
(-1 << 31) & 0xFFFFFFFF => 'NET_SFTP_ATTR_EXTENDED'
);
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
// the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name
// the array for that $this->open5_flags and similarly alter the constant names.
$this->open_flags = array(
0x00000001 => 'NET_SFTP_OPEN_READ',
0x00000002 => 'NET_SFTP_OPEN_WRITE',
0x00000004 => 'NET_SFTP_OPEN_APPEND',
0x00000008 => 'NET_SFTP_OPEN_CREATE',
0x00000010 => 'NET_SFTP_OPEN_TRUNCATE',
0x00000020 => 'NET_SFTP_OPEN_EXCL'
);
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2
// see Net_SFTP::_parseLongname() for an explanation
$this->file_types = array(
1 => 'NET_SFTP_TYPE_REGULAR',
2 => 'NET_SFTP_TYPE_DIRECTORY',
3 => 'NET_SFTP_TYPE_SYMLINK',
4 => 'NET_SFTP_TYPE_SPECIAL',
5 => 'NET_SFTP_TYPE_UNKNOWN',
// the followin types were first defined for use in SFTPv5+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
6 => 'NET_SFTP_TYPE_SOCKET',
7 => 'NET_SFTP_TYPE_CHAR_DEVICE',
8 => 'NET_SFTP_TYPE_BLOCK_DEVICE',
9 => 'NET_SFTP_TYPE_FIFO'
);
$this->_define_array(
$this->packet_types,
$this->status_codes,
$this->attributes,
$this->open_flags,
$this->file_types
);
if (!defined('NET_SFTP_QUEUE_SIZE')) {
define('NET_SFTP_QUEUE_SIZE', 32);
}
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param string $host
* @param int $port
* @param int $timeout
* @access public
*/
function Net_SFTP($host, $port = 22, $timeout = 10)
{
$this->__construct($host, $port, $timeout);
}
/**
* Login
*
* @param string $username
* @param string $password
* @return bool
* @access public
*/
function login($username)
{
$args = func_get_args();
if (!call_user_func_array(array(&$this, '_login'), $args)) {
return false;
}
$this->window_size_server_to_client[NET_SFTP_CHANNEL] = $this->window_size;
$packet = pack(
'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
NET_SFTP_CHANNEL,
$this->window_size,
0x4000
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;
$response = $this->_get_channel_packet(NET_SFTP_CHANNEL, true);
if ($response === false) {
return false;
}
$packet = pack(
'CNNa*CNa*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[NET_SFTP_CHANNEL],
strlen('subsystem'),
'subsystem',
1,
strlen('sftp'),
'sftp'
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
$response = $this->_get_channel_packet(NET_SFTP_CHANNEL, true);
if ($response === false) {
// from PuTTY's psftp.exe
$command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" .
"test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" .
"exec sftp-server";
// we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does
// is redundant
$packet = pack(
'CNNa*CNa*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[NET_SFTP_CHANNEL],
strlen('exec'),
'exec',
1,
strlen($command),
$command
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
$response = $this->_get_channel_packet(NET_SFTP_CHANNEL, true);
if ($response === false) {
return false;
}
}
$this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
if (!$this->_send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) {
return false;
}
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_VERSION) {
user_error('Expected SSH_FXP_VERSION');
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nversion', $this->_string_shift($response, 4)));
$this->version = $version;
while (!empty($response)) {
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$key = $this->_string_shift($response, $length);
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$value = $this->_string_shift($response, $length);
$this->extensions[$key] = $value;
}
/*
SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com',
however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's
not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for
one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that
'newline@vandyke.com' would.
*/
/*
if (isset($this->extensions['newline@vandyke.com'])) {
$this->extensions['newline'] = $this->extensions['newline@vandyke.com'];
unset($this->extensions['newline@vandyke.com']);
}
*/
$this->use_request_id = true;
/*
A Note on SFTPv4/5/6 support:
states the following:
"If the client wishes to interoperate with servers that support noncontiguous version
numbers it SHOULD send '3'"
Given that the server only sends its version number after the client has already done so, the above
seems to be suggesting that v3 should be the default version. This makes sense given that v3 is the
most popular.
states the following;
"If the server did not send the "versions" extension, or the version-from-list was not included, the
server MAY send a status response describing the failure, but MUST then close the channel without
processing any further requests."
So what do you do if you have a client whose initial SSH_FXP_INIT packet says it implements v3 and
a server whose initial SSH_FXP_VERSION reply says it implements v4 and only v4? If it only implements
v4, the "versions" extension is likely not going to have been sent so version re-negotiation as discussed
in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what Net_SFTP would do is close the
channel and reopen it with a new and updated SSH_FXP_INIT packet.
*/
switch ($this->version) {
case 2:
case 3:
break;
default:
return false;
}
$this->pwd = $this->_realpath('.');
$this->_update_stat_cache($this->pwd, array());
return true;
}
/**
* Disable the stat cache
*
* @access public
*/
function disableStatCache()
{
$this->use_stat_cache = false;
}
/**
* Enable the stat cache
*
* @access public
*/
function enableStatCache()
{
$this->use_stat_cache = true;
}
/**
* Clear the stat cache
*
* @access public
*/
function clearStatCache()
{
$this->stat_cache = array();
}
/**
* Enable path canonicalization
*
* @access public
*/
function enablePathCanonicalization()
{
$this->canonicalize_paths = true;
}
/**
* Enable path canonicalization
*
* @access public
*/
function disablePathCanonicalization()
{
$this->canonicalize_paths = false;
}
/**
* Returns the current directory name
*
* @return mixed
* @access public
*/
function pwd()
{
return $this->pwd;
}
/**
* Logs errors
*
* @param string $response
* @param int $status
* @access public
*/
function _logError($response, $status = -1)
{
if ($status == -1) {
if (strlen($response) < 4) {
return;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
}
$error = $this->status_codes[$status];
if ($this->version > 2 || strlen($response) < 4) {
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length);
} else {
$this->sftp_errors[] = $error;
}
}
/**
* Returns canonicalized absolute pathname
*
* realpath() expands all symbolic links and resolves references to '/./', '/../' and extra '/' characters in the input
* path and returns the canonicalized absolute pathname.
*
* @param string $path
* @return mixed
* @access public
*/
function realpath($path)
{
return $this->_realpath($path);
}
/**
* Canonicalize the Server-Side Path Name
*
* SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns
* the absolute (canonicalized) path.
*
* If canonicalize_paths has been disabled using disablePathCanonicalization(), $path is returned as-is.
*
* @see self::chdir()
* @see self::disablePathCanonicalization()
* @param string $path
* @return mixed
* @access private
*/
function _realpath($path)
{
if (!$this->canonicalize_paths) {
return $path;
}
if ($this->pwd === false) {
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
return false;
}
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_NAME:
// although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following
// should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
// at is the first part and that part is defined the same in SFTP versions 3 through 6.
$this->_string_shift($response, 4); // skip over the count - it should be 1, anyway
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
return $this->_string_shift($response, $length);
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
return false;
}
}
if ($path[0] != '/') {
$path = $this->pwd . '/' . $path;
}
$path = explode('/', $path);
$new = array();
foreach ($path as $dir) {
if (!strlen($dir)) {
continue;
}
switch ($dir) {
case '..':
array_pop($new);
case '.':
break;
default:
$new[] = $dir;
}
}
return '/' . implode('/', $new);
}
/**
* Changes the current directory
*
* @param string $dir
* @return bool
* @access public
*/
function chdir($dir)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
// assume current dir if $dir is empty
if ($dir === '') {
$dir = './';
// suffix a slash if needed
} elseif ($dir[strlen($dir) - 1] != '/') {
$dir.= '/';
}
$dir = $this->_realpath($dir);
// confirm that $dir is, in fact, a valid directory
if ($this->use_stat_cache && is_array($this->_query_stat_cache($dir))) {
$this->pwd = $dir;
return true;
}
// we could do a stat on the alleged $dir to see if it's a directory but that doesn't tell us
// the currently logged in user has the appropriate permissions or not. maybe you could see if
// the file's uid / gid match the currently logged in user's uid / gid but how there's no easy
// way to get those with SFTP
if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
return false;
}
// see Net_SFTP::nlist() for a more thorough explanation of the following
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
$handle = substr($response, 4);
break;
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}
if (!$this->_close_handle($handle)) {
return false;
}
$this->_update_stat_cache($dir, array());
$this->pwd = $dir;
return true;
}
/**
* Returns a list of files in the given directory
*
* @param string $dir
* @param bool $recursive
* @return mixed
* @access public
*/
function nlist($dir = '.', $recursive = false)
{
return $this->_nlist_helper($dir, $recursive, '');
}
/**
* Helper method for nlist
*
* @param string $dir
* @param bool $recursive
* @param string $relativeDir
* @return mixed
* @access private
*/
function _nlist_helper($dir, $recursive, $relativeDir)
{
$files = $this->_list($dir, false);
if (!$recursive || $files === false) {
return $files;
}
$result = array();
foreach ($files as $value) {
if ($value == '.' || $value == '..') {
if ($relativeDir == '') {
$result[] = $value;
}
continue;
}
if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) {
$temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/');
$result = array_merge($result, $temp);
} else {
$result[] = $relativeDir . $value;
}
}
return $result;
}
/**
* Returns a detailed list of files in the given directory
*
* @param string $dir
* @param bool $recursive
* @return mixed
* @access public
*/
function rawlist($dir = '.', $recursive = false)
{
$files = $this->_list($dir, true);
if (!$recursive || $files === false) {
return $files;
}
static $depth = 0;
foreach ($files as $key => $value) {
if ($depth != 0 && $key == '..') {
unset($files[$key]);
continue;
}
$is_directory = false;
if ($key != '.' && $key != '..') {
if ($this->use_stat_cache) {
$is_directory = is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)));
} else {
$stat = $this->lstat($dir . '/' . $key);
$is_directory = $stat && $stat['type'] === NET_SFTP_TYPE_DIRECTORY;
}
}
if ($is_directory) {
$depth++;
$files[$key] = $this->rawlist($dir . '/' . $key, true);
$depth--;
} else {
$files[$key] = (object) $value;
}
}
return $files;
}
/**
* Reads a list, be it detailed or not, of files in the given directory
*
* @param string $dir
* @param bool $raw
* @return mixed
* @access private
*/
function _list($dir, $raw = true)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$dir = $this->_realpath($dir . '/');
if ($dir === false) {
return false;
}
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2
if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
return false;
}
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.2
// since 'handle' is the last field in the SSH_FXP_HANDLE packet, we'll just remove the first four bytes that
// represent the length of the string and leave it at that
$handle = substr($response, 4);
break;
case NET_SFTP_STATUS:
// presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}
$this->_update_stat_cache($dir, array());
$contents = array();
while (true) {
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2
// why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many
// SSH_MSG_CHANNEL_DATA messages is not known to me.
if (!$this->_send_sftp_packet(NET_SFTP_READDIR, pack('Na*', strlen($handle), $handle))) {
return false;
}
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_NAME:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Ncount', $this->_string_shift($response, 4)));
for ($i = 0; $i < $count; $i++) {
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$shortname = $this->_string_shift($response, $length);
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$longname = $this->_string_shift($response, $length);
$attributes = $this->_parseAttributes($response);
if (!isset($attributes['type'])) {
$fileType = $this->_parseLongname($longname);
if ($fileType) {
$attributes['type'] = $fileType;
}
}
$contents[$shortname] = $attributes + array('filename' => $shortname);
if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
$this->_update_stat_cache($dir . '/' . $shortname, array());
} else {
if ($shortname == '..') {
$temp = $this->_realpath($dir . '/..') . '/.';
} else {
$temp = $dir . '/' . $shortname;
}
$this->_update_stat_cache($temp, (object) array('lstat' => $attributes));
}
// SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
// final SSH_FXP_STATUS packet should tell us that, already.
}
break;
case NET_SFTP_STATUS:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_EOF) {
$this->_logError($response, $status);
return false;
}
break 2;
default:
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
return false;
}
}
if (!$this->_close_handle($handle)) {
return false;
}
if (count($this->sortOptions)) {
uasort($contents, array(&$this, '_comparator'));
}
return $raw ? $contents : array_keys($contents);
}
/**
* Compares two rawlist entries using parameters set by setListOrder()
*
* Intended for use with uasort()
*
* @param array $a
* @param array $b
* @return int
* @access private
*/
function _comparator($a, $b)
{
switch (true) {
case $a['filename'] === '.' || $b['filename'] === '.':
if ($a['filename'] === $b['filename']) {
return 0;
}
return $a['filename'] === '.' ? -1 : 1;
case $a['filename'] === '..' || $b['filename'] === '..':
if ($a['filename'] === $b['filename']) {
return 0;
}
return $a['filename'] === '..' ? -1 : 1;
case isset($a['type']) && $a['type'] === NET_SFTP_TYPE_DIRECTORY:
if (!isset($b['type'])) {
return 1;
}
if ($b['type'] !== $a['type']) {
return -1;
}
break;
case isset($b['type']) && $b['type'] === NET_SFTP_TYPE_DIRECTORY:
return 1;
}
foreach ($this->sortOptions as $sort => $order) {
if (!isset($a[$sort]) || !isset($b[$sort])) {
if (isset($a[$sort])) {
return -1;
}
if (isset($b[$sort])) {
return 1;
}
return 0;
}
switch ($sort) {
case 'filename':
$result = strcasecmp($a['filename'], $b['filename']);
if ($result) {
return $order === SORT_DESC ? -$result : $result;
}
break;
case 'permissions':
case 'mode':
$a[$sort]&= 07777;
$b[$sort]&= 07777;
default:
if ($a[$sort] === $b[$sort]) {
break;
}
return $order === SORT_ASC ? $a[$sort] - $b[$sort] : $b[$sort] - $a[$sort];
}
}
}
/**
* Defines how nlist() and rawlist() will be sorted - if at all.
*
* If sorting is enabled directories and files will be sorted independently with
* directories appearing before files in the resultant array that is returned.
*
* Any parameter returned by stat is a valid sort parameter for this function.
* Filename comparisons are case insensitive.
*
* Examples:
*
* $sftp->setListOrder('filename', SORT_ASC);
* $sftp->setListOrder('size', SORT_DESC, 'filename', SORT_ASC);
* $sftp->setListOrder(true);
* Separates directories from files but doesn't do any sorting beyond that
* $sftp->setListOrder();
* Don't do any sort of sorting
*
* @access public
*/
function setListOrder()
{
$this->sortOptions = array();
$args = func_get_args();
if (empty($args)) {
return;
}
$len = count($args) & 0x7FFFFFFE;
for ($i = 0; $i < $len; $i+=2) {
$this->sortOptions[$args[$i]] = $args[$i + 1];
}
if (!count($this->sortOptions)) {
$this->sortOptions = array('bogus' => true);
}
}
/**
* Returns the file size, in bytes, or false, on failure
*
* Files larger than 4GB will show up as being exactly 4GB.
*
* @param string $filename
* @return mixed
* @access public
*/
function size($filename)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$result = $this->stat($filename);
if ($result === false) {
return false;
}
return isset($result['size']) ? $result['size'] : -1;
}
/**
* Save files / directories to cache
*
* @param string $path
* @param mixed $value
* @access private
*/
function _update_stat_cache($path, $value)
{
if ($this->use_stat_cache === false) {
return;
}
// preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/'))
$dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
$temp = &$this->stat_cache;
$max = count($dirs) - 1;
foreach ($dirs as $i => $dir) {
// if $temp is an object that means one of two things.
// 1. a file was deleted and changed to a directory behind phpseclib's back
// 2. it's a symlink. when lstat is done it's unclear what it's a symlink to
if (is_object($temp)) {
$temp = array();
}
if (!isset($temp[$dir])) {
$temp[$dir] = array();
}
if ($i === $max) {
if (is_object($temp[$dir]) && is_object($value)) {
if (!isset($value->stat) && isset($temp[$dir]->stat)) {
$value->stat = $temp[$dir]->stat;
}
if (!isset($value->lstat) && isset($temp[$dir]->lstat)) {
$value->lstat = $temp[$dir]->lstat;
}
}
$temp[$dir] = $value;
break;
}
$temp = &$temp[$dir];
}
}
/**
* Remove files / directories from cache
*
* @param string $path
* @return bool
* @access private
*/
function _remove_from_stat_cache($path)
{
$dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
$temp = &$this->stat_cache;
$max = count($dirs) - 1;
foreach ($dirs as $i => $dir) {
if ($i === $max) {
unset($temp[$dir]);
return true;
}
if (!isset($temp[$dir])) {
return false;
}
$temp = &$temp[$dir];
}
}
/**
* Checks cache for path
*
* Mainly used by file_exists
*
* @param string $dir
* @return mixed
* @access private
*/
function _query_stat_cache($path)
{
$dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
$temp = &$this->stat_cache;
foreach ($dirs as $dir) {
if (!isset($temp[$dir])) {
return null;
}
$temp = &$temp[$dir];
}
return $temp;
}
/**
* Returns general information about a file.
*
* Returns an array on success and false otherwise.
*
* @param string $filename
* @return mixed
* @access public
*/
function stat($filename)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$filename = $this->_realpath($filename);
if ($filename === false) {
return false;
}
if ($this->use_stat_cache) {
$result = $this->_query_stat_cache($filename);
if (is_array($result) && isset($result['.']) && isset($result['.']->stat)) {
return $result['.']->stat;
}
if (is_object($result) && isset($result->stat)) {
return $result->stat;
}
}
$stat = $this->_stat($filename, NET_SFTP_STAT);
if ($stat === false) {
$this->_remove_from_stat_cache($filename);
return false;
}
if (isset($stat['type'])) {
if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) array('stat' => $stat));
return $stat;
}
$pwd = $this->pwd;
$stat['type'] = $this->chdir($filename) ?
NET_SFTP_TYPE_DIRECTORY :
NET_SFTP_TYPE_REGULAR;
$this->pwd = $pwd;
if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) array('stat' => $stat));
return $stat;
}
/**
* Returns general information about a file or symbolic link.
*
* Returns an array on success and false otherwise.
*
* @param string $filename
* @return mixed
* @access public
*/
function lstat($filename)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$filename = $this->_realpath($filename);
if ($filename === false) {
return false;
}
if ($this->use_stat_cache) {
$result = $this->_query_stat_cache($filename);
if (is_array($result) && isset($result['.']) && isset($result['.']->lstat)) {
return $result['.']->lstat;
}
if (is_object($result) && isset($result->lstat)) {
return $result->lstat;
}
}
$lstat = $this->_stat($filename, NET_SFTP_LSTAT);
if ($lstat === false) {
$this->_remove_from_stat_cache($filename);
return false;
}
if (isset($lstat['type'])) {
if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
return $lstat;
}
$stat = $this->_stat($filename, NET_SFTP_STAT);
if ($lstat != $stat) {
$lstat = array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK));
$this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
return $stat;
}
$pwd = $this->pwd;
$lstat['type'] = $this->chdir($filename) ?
NET_SFTP_TYPE_DIRECTORY :
NET_SFTP_TYPE_REGULAR;
$this->pwd = $pwd;
if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
return $lstat;
}
/**
* Returns general information about a file or symbolic link
*
* Determines information without calling Net_SFTP::realpath().
* The second parameter can be either NET_SFTP_STAT or NET_SFTP_LSTAT.
*
* @param string $filename
* @param int $type
* @return mixed
* @access private
*/
function _stat($filename, $type)
{
// SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
$packet = pack('Na*', strlen($filename), $filename);
if (!$this->_send_sftp_packet($type, $packet)) {
return false;
}
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_ATTRS:
return $this->_parseAttributes($response);
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
}
user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
return false;
}
/**
* Truncates a file to a given length
*
* @param string $filename
* @param int $new_size
* @return bool
* @access public
*/
function truncate($filename, $new_size)
{
$attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 4294967296, $new_size); // 4294967296 == 0x100000000 == 1<<32
return $this->_setstat($filename, $attr, false);
}
/**
* Sets access and modification time of file.
*
* If the file does not exist, it will be created.
*
* @param string $filename
* @param int $time
* @param int $atime
* @return bool
* @access public
*/
function touch($filename, $time = null, $atime = null)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$filename = $this->_realpath($filename);
if ($filename === false) {
return false;
}
if (!isset($time)) {
$time = time();
}
if (!isset($atime)) {
$atime = $time;
}
$flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL;
$attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime);
$packet = pack('Na*Na*', strlen($filename), $filename, $flags, $attr);
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
return false;
}
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
return $this->_close_handle(substr($response, 4));
case NET_SFTP_STATUS:
$this->_logError($response);
break;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}
return $this->_setstat($filename, $attr, false);
}
/**
* Changes file or directory owner
*
* Returns true on success or false on error.
*
* @param string $filename
* @param int $uid
* @param bool $recursive
* @return bool
* @access public
*/
function chown($filename, $uid, $recursive = false)
{
// quoting from ,
// "if the owner or group is specified as -1, then that ID is not changed"
$attr = pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1);
return $this->_setstat($filename, $attr, $recursive);
}
/**
* Changes file or directory group
*
* Returns true on success or false on error.
*
* @param string $filename
* @param int $gid
* @param bool $recursive
* @return bool
* @access public
*/
function chgrp($filename, $gid, $recursive = false)
{
$attr = pack('N3', NET_SFTP_ATTR_UIDGID, -1, $gid);
return $this->_setstat($filename, $attr, $recursive);
}
/**
* Set permissions on a file.
*
* Returns the new file permissions on success or false on error.
* If $recursive is true than this just returns true or false.
*
* @param int $mode
* @param string $filename
* @param bool $recursive
* @return mixed
* @access public
*/
function chmod($mode, $filename, $recursive = false)
{
if (is_string($mode) && is_int($filename)) {
$temp = $mode;
$mode = $filename;
$filename = $temp;
}
$attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
if (!$this->_setstat($filename, $attr, $recursive)) {
return false;
}
if ($recursive) {
return true;
}
$filename = $this->realpath($filename);
// rather than return what the permissions *should* be, we'll return what they actually are. this will also
// tell us if the file actually exists.
// incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
$packet = pack('Na*', strlen($filename), $filename);
if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) {
return false;
}
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_ATTRS:
$attrs = $this->_parseAttributes($response);
return $attrs['permissions'];
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
}
user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
return false;
}
/**
* Sets information about a file
*
* @param string $filename
* @param string $attr
* @param bool $recursive
* @return bool
* @access private
*/
function _setstat($filename, $attr, $recursive)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$filename = $this->_realpath($filename);
if ($filename === false) {
return false;
}
$this->_remove_from_stat_cache($filename);
if ($recursive) {
$i = 0;
$result = $this->_setstat_recursive($filename, $attr, $i);
$this->_read_put_responses($i);
return $result;
}
// SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to
// SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT.
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) {
return false;
}
/*
"Because some systems must use separate system calls to set various attributes, it is possible that a failure
response will be returned, but yet some of the attributes may be have been successfully modified. If possible,
servers SHOULD avoid this situation; however, clients MUST be aware that this is possible."
-- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6
*/
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
return false;
}
return true;
}
/**
* Recursively sets information on directories on the SFTP server
*
* Minimizes directory lookups and SSH_FXP_STATUS requests for speed.
*
* @param string $path
* @param string $attr
* @param int $i
* @return bool
* @access private
*/
function _setstat_recursive($path, $attr, &$i)
{
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
$entries = $this->_list($path, true);
if ($entries === false) {
return $this->_setstat($path, $attr, false);
}
// normally $entries would have at least . and .. but it might not if the directories
// permissions didn't allow reading
if (empty($entries)) {
return false;
}
unset($entries['.'], $entries['..']);
foreach ($entries as $filename => $props) {
if (!isset($props['type'])) {
return false;
}
$temp = $path . '/' . $filename;
if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
if (!$this->_setstat_recursive($temp, $attr, $i)) {
return false;
}
} else {
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($temp), $temp, $attr))) {
return false;
}
$i++;
if ($i >= NET_SFTP_QUEUE_SIZE) {
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
}
}
}
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($path), $path, $attr))) {
return false;
}
$i++;
if ($i >= NET_SFTP_QUEUE_SIZE) {
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
}
return true;
}
/**
* Return the target of a symbolic link
*
* @param string $link
* @return mixed
* @access public
*/
function readlink($link)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$link = $this->_realpath($link);
if (!$this->_send_sftp_packet(NET_SFTP_READLINK, pack('Na*', strlen($link), $link))) {
return false;
}
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_NAME:
break;
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Ncount', $this->_string_shift($response, 4)));
// the file isn't a symlink
if (!$count) {
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
return $this->_string_shift($response, $length);
}
/**
* Create a symlink
*
* symlink() creates a symbolic link to the existing target with the specified name link.
*
* @param string $target
* @param string $link
* @return bool
* @access public
*/
function symlink($target, $link)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
//$target = $this->_realpath($target);
$link = $this->_realpath($link);
$packet = pack('Na*Na*', strlen($target), $target, strlen($link), $link);
if (!$this->_send_sftp_packet(NET_SFTP_SYMLINK, $packet)) {
return false;
}
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
return false;
}
return true;
}
/**
* Creates a directory.
*
* @param string $dir
* @return bool
* @access public
*/
function mkdir($dir, $mode = -1, $recursive = false)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$dir = $this->_realpath($dir);
// by not providing any permissions, hopefully the server will use the logged in users umask - their
// default permissions.
$attr = $mode == -1 ? "\0\0\0\0" : pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
if ($recursive) {
$dirs = explode('/', preg_replace('#/(?=/)|/$#', '', $dir));
if (empty($dirs[0])) {
array_shift($dirs);
$dirs[0] = '/' . $dirs[0];
}
for ($i = 0; $i < count($dirs); $i++) {
$temp = array_slice($dirs, 0, $i + 1);
$temp = implode('/', $temp);
$result = $this->_mkdir_helper($temp, $attr);
}
return $result;
}
return $this->_mkdir_helper($dir, $attr);
}
/**
* Helper function for directory creation
*
* @param string $dir
* @return bool
* @access private
*/
function _mkdir_helper($dir, $attr)
{
if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*a*', strlen($dir), $dir, $attr))) {
return false;
}
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
return false;
}
return true;
}
/**
* Removes a directory.
*
* @param string $dir
* @return bool
* @access public
*/
function rmdir($dir)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$dir = $this->_realpath($dir);
if ($dir === false) {
return false;
}
if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($dir), $dir))) {
return false;
}
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
// presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
$this->_logError($response, $status);
return false;
}
$this->_remove_from_stat_cache($dir);
// the following will do a soft delete, which would be useful if you deleted a file
// and then tried to do a stat on the deleted file. the above, in contrast, does
// a hard delete
//$this->_update_stat_cache($dir, false);
return true;
}
/**
* Uploads a file to the SFTP server.
*
* By default, Net_SFTP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
* So, for example, if you set $data to 'filename.ext' and then do Net_SFTP::get(), you will get a file, twelve bytes
* long, containing 'filename.ext' as its contents.
*
* Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will
* contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
* large $remote_file will be, as well.
*
* If $data is a resource then it'll be used as a resource instead.
*
*
* Setting $mode to NET_SFTP_CALLBACK will use $data as callback function, which gets only one parameter -- number
* of bytes to return, and returns a string if there is some data or null if there is no more data
*
* Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
* care of that, yourself.
*
* $mode can take an additional two parameters - NET_SFTP_RESUME and NET_SFTP_RESUME_START. These are bitwise AND'd with
* $mode. So if you want to resume upload of a 300mb file on the local file system you'd set $mode to the following:
*
* NET_SFTP_LOCAL_FILE | NET_SFTP_RESUME
*
* If you wanted to simply append the full contents of a local file to the full contents of a remote file you'd replace
* NET_SFTP_RESUME with NET_SFTP_RESUME_START.
*
* If $mode & (NET_SFTP_RESUME | NET_SFTP_RESUME_START) then NET_SFTP_RESUME_START will be assumed.
*
* $start and $local_start give you more fine grained control over this process and take precident over NET_SFTP_RESUME
* when they're non-negative. ie. $start could let you write at the end of a file (like NET_SFTP_RESUME) or in the middle
* of one. $local_start could let you start your reading from the end of a file (like NET_SFTP_RESUME_START) or in the
* middle of one.
*
* Setting $local_start to > 0 or $mode | NET_SFTP_RESUME_START doesn't do anything unless $mode | NET_SFTP_LOCAL_FILE.
*
* @param string $remote_file
* @param string|resource $data
* @param int $mode
* @param int $start
* @param int $local_start
* @param callable|null $progressCallback
* @return bool
* @access public
* @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode().
*/
function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_start = -1, $progressCallback = null)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$remote_file = $this->_realpath($remote_file);
if ($remote_file === false) {
return false;
}
$this->_remove_from_stat_cache($remote_file);
$flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE;
// according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file."
// in practice, it doesn't seem to do that.
//$flags|= ($mode & NET_SFTP_RESUME) ? NET_SFTP_OPEN_APPEND : NET_SFTP_OPEN_TRUNCATE;
if ($start >= 0) {
$offset = $start;
} elseif ($mode & NET_SFTP_RESUME) {
// if NET_SFTP_OPEN_APPEND worked as it should _size() wouldn't need to be called
$size = $this->size($remote_file);
$offset = $size !== false ? $size : 0;
} else {
$offset = 0;
$flags|= NET_SFTP_OPEN_TRUNCATE;
}
$packet = pack('Na*N2', strlen($remote_file), $remote_file, $flags, 0);
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
return false;
}
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
$handle = substr($response, 4);
break;
case NET_SFTP_STATUS:
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
$dataCallback = false;
switch (true) {
case $mode & NET_SFTP_CALLBACK:
if (!is_callable($data)) {
user_error("\$data should be is_callable if you set NET_SFTP_CALLBACK flag");
}
$dataCallback = $data;
// do nothing
break;
case is_resource($data):
$mode = $mode & ~NET_SFTP_LOCAL_FILE;
$info = stream_get_meta_data($data);
if ($info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') {
$fp = fopen('php://memory', 'w+');
stream_copy_to_stream($data, $fp);
rewind($fp);
} else {
$fp = $data;
}
break;
case $mode & NET_SFTP_LOCAL_FILE:
if (!is_file($data)) {
user_error("$data is not a valid file");
return false;
}
$fp = @fopen($data, 'rb');
if (!$fp) {
return false;
}
}
if (isset($fp)) {
$stat = fstat($fp);
$size = !empty($stat) ? $stat['size'] : 0;
if ($local_start >= 0) {
fseek($fp, $local_start);
$size-= $local_start;
}
} elseif ($dataCallback) {
$size = 0;
} else {
$size = strlen($data);
}
$sent = 0;
$size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
$sftp_packet_size = 4096; // PuTTY uses 4096
// make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header"
$sftp_packet_size-= strlen($handle) + 25;
$i = 0;
while ($dataCallback || ($size === 0 || $sent < $size)) {
if ($dataCallback) {
$temp = call_user_func($dataCallback, $sftp_packet_size);
if (is_null($temp)) {
break;
}
} else {
$temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size);
if ($temp === false || $temp === '') {
break;
}
}
$subtemp = $offset + $sent;
$packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp);
if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) {
if ($mode & NET_SFTP_LOCAL_FILE) {
fclose($fp);
}
return false;
}
$sent+= strlen($temp);
if (is_callable($progressCallback)) {
call_user_func($progressCallback, $sent);
}
$i++;
if ($i == NET_SFTP_QUEUE_SIZE) {
if (!$this->_read_put_responses($i)) {
$i = 0;
break;
}
$i = 0;
}
}
if (!$this->_read_put_responses($i)) {
if ($mode & NET_SFTP_LOCAL_FILE) {
fclose($fp);
}
$this->_close_handle($handle);
return false;
}
if ($mode & NET_SFTP_LOCAL_FILE) {
fclose($fp);
}
return $this->_close_handle($handle);
}
/**
* Reads multiple successive SSH_FXP_WRITE responses
*
* Sending an SSH_FXP_WRITE packet and immediately reading its response isn't as efficient as blindly sending out $i
* SSH_FXP_WRITEs, in succession, and then reading $i responses.
*
* @param int $i
* @return bool
* @access private
*/
function _read_put_responses($i)
{
while ($i--) {
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
break;
}
}
return $i < 0;
}
/**
* Close handle
*
* @param string $handle
* @return bool
* @access private
*/
function _close_handle($handle)
{
if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
return false;
}
// "The client MUST release all resources associated with the handle regardless of the status."
// -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
return false;
}
return true;
}
/**
* Downloads a file from the SFTP server.
*
* Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
* the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
* operation.
*
* $offset and $length can be used to download files in chunks.
*
* @param string $remote_file
* @param string $local_file
* @param int $offset
* @param int $length
* @return mixed
* @access public
*/
function get($remote_file, $local_file = false, $offset = 0, $length = -1)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$remote_file = $this->_realpath($remote_file);
if ($remote_file === false) {
return false;
}
$packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0);
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
return false;
}
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
$handle = substr($response, 4);
break;
case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}
if (is_resource($local_file)) {
$fp = $local_file;
$stat = fstat($fp);
$res_offset = $stat['size'];
} else {
$res_offset = 0;
if ($local_file !== false) {
$fp = fopen($local_file, 'wb');
if (!$fp) {
return false;
}
} else {
$content = '';
}
}
$fclose_check = $local_file !== false && !is_resource($local_file);
$start = $offset;
$read = 0;
while (true) {
$i = 0;
while ($i < NET_SFTP_QUEUE_SIZE && ($length < 0 || $read < $length)) {
$tempoffset = $start + $read;
$packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet;
$packet = pack('Na*N3', strlen($handle), $handle, $tempoffset / 4294967296, $tempoffset, $packet_size);
if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet, $i)) {
if ($fclose_check) {
fclose($fp);
}
return false;
}
$packet = null;
$read+= $packet_size;
$i++;
}
if (!$i) {
break;
}
$packets_sent = $i - 1;
$clear_responses = false;
while ($i > 0) {
$i--;
if ($clear_responses) {
$this->_get_sftp_packet($packets_sent - $i);
continue;
} else {
$response = $this->_get_sftp_packet($packets_sent - $i);
}
switch ($this->packet_type) {
case NET_SFTP_DATA:
$temp = substr($response, 4);
$offset+= strlen($temp);
if ($local_file === false) {
$content.= $temp;
} else {
fputs($fp, $temp);
}
$temp = null;
break;
case NET_SFTP_STATUS:
// could, in theory, return false if !strlen($content) but we'll hold off for the time being
$this->_logError($response);
$clear_responses = true; // don't break out of the loop yet, so we can read the remaining responses
break;
default:
if ($fclose_check) {
fclose($fp);
}
user_error('Expected SSH_FX_DATA or SSH_FXP_STATUS');
}
$response = null;
}
if ($clear_responses) {
break;
}
}
if ($length > 0 && $length <= $offset - $start) {
if ($local_file === false) {
$content = substr($content, 0, $length);
} else {
ftruncate($fp, $length + $res_offset);
}
}
if ($fclose_check) {
fclose($fp);
}
if (!$this->_close_handle($handle)) {
return false;
}
// if $content isn't set that means a file was written to
return isset($content) ? $content : true;
}
/**
* Deletes a file on the SFTP server.
*
* @param string $path
* @param bool $recursive
* @return bool
* @access public
*/
function delete($path, $recursive = true)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
if (is_object($path)) {
// It's an object. Cast it as string before we check anything else.
$path = (string) $path;
}
if (!is_string($path) || $path == '') {
return false;
}
$path = $this->_realpath($path);
if ($path === false) {
return false;
}
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path))) {
return false;
}
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}
// if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
if (!$recursive) {
return false;
}
$i = 0;
$result = $this->_delete_recursive($path, $i);
$this->_read_put_responses($i);
return $result;
}
$this->_remove_from_stat_cache($path);
return true;
}
/**
* Recursively deletes directories on the SFTP server
*
* Minimizes directory lookups and SSH_FXP_STATUS requests for speed.
*
* @param string $path
* @param int $i
* @return bool
* @access private
*/
function _delete_recursive($path, &$i)
{
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
$entries = $this->_list($path, true);
// normally $entries would have at least . and .. but it might not if the directories
// permissions didn't allow reading
if (empty($entries)) {
return false;
}
unset($entries['.'], $entries['..']);
foreach ($entries as $filename => $props) {
if (!isset($props['type'])) {
return false;
}
$temp = $path . '/' . $filename;
if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
if (!$this->_delete_recursive($temp, $i)) {
return false;
}
} else {
if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($temp), $temp))) {
return false;
}
$this->_remove_from_stat_cache($temp);
$i++;
if ($i >= NET_SFTP_QUEUE_SIZE) {
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
}
}
}
if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) {
return false;
}
$this->_remove_from_stat_cache($path);
$i++;
if ($i >= NET_SFTP_QUEUE_SIZE) {
if (!$this->_read_put_responses($i)) {
return false;
}
$i = 0;
}
return true;
}
/**
* Checks whether a file or directory exists
*
* @param string $path
* @return bool
* @access public
*/
function file_exists($path)
{
if ($this->use_stat_cache) {
$path = $this->_realpath($path);
$result = $this->_query_stat_cache($path);
if (isset($result)) {
// return true if $result is an array or if it's an stdClass object
return $result !== false;
}
}
return $this->stat($path) !== false;
}
/**
* Tells whether the filename is a directory
*
* @param string $path
* @return bool
* @access public
*/
function is_dir($path)
{
$result = $this->_get_stat_cache_prop($path, 'type');
if ($result === false) {
return false;
}
return $result === NET_SFTP_TYPE_DIRECTORY;
}
/**
* Tells whether the filename is a regular file
*
* @param string $path
* @return bool
* @access public
*/
function is_file($path)
{
$result = $this->_get_stat_cache_prop($path, 'type');
if ($result === false) {
return false;
}
return $result === NET_SFTP_TYPE_REGULAR;
}
/**
* Tells whether the filename is a symbolic link
*
* @param string $path
* @return bool
* @access public
*/
function is_link($path)
{
$result = $this->_get_lstat_cache_prop($path, 'type');
if ($result === false) {
return false;
}
return $result === NET_SFTP_TYPE_SYMLINK;
}
/**
* Tells whether a file exists and is readable
*
* @param string $path
* @return bool
* @access public
*/
function is_readable($path)
{
$path = $this->_realpath($path);
$packet = pack('Na*N2', strlen($path), $path, NET_SFTP_OPEN_READ, 0);
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
return false;
}
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
return true;
case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}
}
/**
* Tells whether the filename is writable
*
* @param string $path
* @return bool
* @access public
*/
function is_writable($path)
{
$path = $this->_realpath($path);
$packet = pack('Na*N2', strlen($path), $path, NET_SFTP_OPEN_WRITE, 0);
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
return false;
}
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_HANDLE:
return true;
case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
}
}
/**
* Tells whether the filename is writeable
*
* Alias of is_writable
*
* @param string $path
* @return bool
* @access public
*/
function is_writeable($path)
{
return $this->is_writable($path);
}
/**
* Gets last access time of file
*
* @param string $path
* @return mixed
* @access public
*/
function fileatime($path)
{
return $this->_get_stat_cache_prop($path, 'atime');
}
/**
* Gets file modification time
*
* @param string $path
* @return mixed
* @access public
*/
function filemtime($path)
{
return $this->_get_stat_cache_prop($path, 'mtime');
}
/**
* Gets file permissions
*
* @param string $path
* @return mixed
* @access public
*/
function fileperms($path)
{
return $this->_get_stat_cache_prop($path, 'permissions');
}
/**
* Gets file owner
*
* @param string $path
* @return mixed
* @access public
*/
function fileowner($path)
{
return $this->_get_stat_cache_prop($path, 'uid');
}
/**
* Gets file group
*
* @param string $path
* @return mixed
* @access public
*/
function filegroup($path)
{
return $this->_get_stat_cache_prop($path, 'gid');
}
/**
* Gets file size
*
* @param string $path
* @return mixed
* @access public
*/
function filesize($path)
{
return $this->_get_stat_cache_prop($path, 'size');
}
/**
* Gets file type
*
* @param string $path
* @return mixed
* @access public
*/
function filetype($path)
{
$type = $this->_get_stat_cache_prop($path, 'type');
if ($type === false) {
return false;
}
switch ($type) {
case NET_SFTP_TYPE_BLOCK_DEVICE:
return 'block';
case NET_SFTP_TYPE_CHAR_DEVICE:
return 'char';
case NET_SFTP_TYPE_DIRECTORY:
return 'dir';
case NET_SFTP_TYPE_FIFO:
return 'fifo';
case NET_SFTP_TYPE_REGULAR:
return 'file';
case NET_SFTP_TYPE_SYMLINK:
return 'link';
default:
return false;
}
}
/**
* Return a stat properity
*
* Uses cache if appropriate.
*
* @param string $path
* @param string $prop
* @return mixed
* @access private
*/
function _get_stat_cache_prop($path, $prop)
{
return $this->_get_xstat_cache_prop($path, $prop, 'stat');
}
/**
* Return an lstat properity
*
* Uses cache if appropriate.
*
* @param string $path
* @param string $prop
* @return mixed
* @access private
*/
function _get_lstat_cache_prop($path, $prop)
{
return $this->_get_xstat_cache_prop($path, $prop, 'lstat');
}
/**
* Return a stat or lstat properity
*
* Uses cache if appropriate.
*
* @param string $path
* @param string $prop
* @return mixed
* @access private
*/
function _get_xstat_cache_prop($path, $prop, $type)
{
if ($this->use_stat_cache) {
$path = $this->_realpath($path);
$result = $this->_query_stat_cache($path);
if (is_object($result) && isset($result->$type)) {
return $result->{$type}[$prop];
}
}
$result = $this->$type($path);
if ($result === false || !isset($result[$prop])) {
return false;
}
return $result[$prop];
}
/**
* Renames a file or a directory on the SFTP server
*
* @param string $oldname
* @param string $newname
* @return bool
* @access public
*/
function rename($oldname, $newname)
{
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
return false;
}
$oldname = $this->_realpath($oldname);
$newname = $this->_realpath($newname);
if ($oldname === false || $newname === false) {
return false;
}
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
$packet = pack('Na*Na*', strlen($oldname), $oldname, strlen($newname), $newname);
if (!$this->_send_sftp_packet(NET_SFTP_RENAME, $packet)) {
return false;
}
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
}
// if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_OK) {
$this->_logError($response, $status);
return false;
}
// don't move the stat cache entry over since this operation could very well change the
// atime and mtime attributes
//$this->_update_stat_cache($newname, $this->_query_stat_cache($oldname));
$this->_remove_from_stat_cache($oldname);
$this->_remove_from_stat_cache($newname);
return true;
}
/**
* Parse Attributes
*
* See '7. File Attributes' of draft-ietf-secsh-filexfer-13 for more info.
*
* @param string $response
* @return array
* @access private
*/
function _parseAttributes(&$response)
{
$attr = array();
if (strlen($response) < 4) {
user_error('Malformed file attributes');
return array();
}
extract(unpack('Nflags', $this->_string_shift($response, 4)));
// SFTPv4+ have a type field (a byte) that follows the above flag field
foreach ($this->attributes as $key => $value) {
switch ($flags & $key) {
case NET_SFTP_ATTR_SIZE: // 0x00000001
// The size attribute is defined as an unsigned 64-bit integer.
// The following will use floats on 32-bit platforms, if necessary.
// As can be seen in the BigInteger class, floats are generally
// IEEE 754 binary64 "double precision" on such platforms and
// as such can represent integers of at least 2^50 without loss
// of precision. Interpreted in filesize, 2^50 bytes = 1024 TiB.
$attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8)));
break;
case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only)
if (strlen($response) < 8) {
user_error('Malformed file attributes');
return $attr;
}
$attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8));
break;
case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
$attr+= unpack('Npermissions', $this->_string_shift($response, 4));
// mode == permissions; permissions was the original array key and is retained for bc purposes.
// mode was added because that's the more industry standard terminology
$attr+= array('mode' => $attr['permissions']);
$fileType = $this->_parseMode($attr['permissions']);
if ($fileType !== false) {
$attr+= array('type' => $fileType);
}
break;
case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
if (strlen($response) < 8) {
user_error('Malformed file attributes');
return $attr;
}
$attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8));
break;
case NET_SFTP_ATTR_EXTENDED: // 0x80000000
if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Ncount', $this->_string_shift($response, 4)));
for ($i = 0; $i < $count; $i++) {
if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$key = $this->_string_shift($response, $length);
if (strlen($response) < 4) {
user_error('Malformed file attributes');
return $attr;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$attr[$key] = $this->_string_shift($response, $length);
}
}
}
return $attr;
}
/**
* Attempt to identify the file type
*
* Quoting the SFTP RFC, "Implementations MUST NOT send bits that are not defined" but they seem to anyway
*
* @param int $mode
* @return int
* @access private
*/
function _parseMode($mode)
{
// values come from http://lxr.free-electrons.com/source/include/uapi/linux/stat.h#L12
// see, also, http://linux.die.net/man/2/stat
switch ($mode & 0170000) {// ie. 1111 0000 0000 0000
case 0000000: // no file type specified - figure out the file type using alternative means
return false;
case 0040000:
return NET_SFTP_TYPE_DIRECTORY;
case 0100000:
return NET_SFTP_TYPE_REGULAR;
case 0120000:
return NET_SFTP_TYPE_SYMLINK;
// new types introduced in SFTPv5+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
case 0010000: // named pipe (fifo)
return NET_SFTP_TYPE_FIFO;
case 0020000: // character special
return NET_SFTP_TYPE_CHAR_DEVICE;
case 0060000: // block special
return NET_SFTP_TYPE_BLOCK_DEVICE;
case 0140000: // socket
return NET_SFTP_TYPE_SOCKET;
case 0160000: // whiteout
// "SPECIAL should be used for files that are of
// a known type which cannot be expressed in the protocol"
return NET_SFTP_TYPE_SPECIAL;
default:
return NET_SFTP_TYPE_UNKNOWN;
}
}
/**
* Parse Longname
*
* SFTPv3 doesn't provide any easy way of identifying a file type. You could try to open
* a file as a directory and see if an error is returned or you could try to parse the
* SFTPv3-specific longname field of the SSH_FXP_NAME packet. That's what this function does.
* The result is returned using the
* {@link http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 SFTPv4 type constants}.
*
* If the longname is in an unrecognized format bool(false) is returned.
*
* @param string $longname
* @return mixed
* @access private
*/
function _parseLongname($longname)
{
// http://en.wikipedia.org/wiki/Unix_file_types
// http://en.wikipedia.org/wiki/Filesystem_permissions#Notation_of_traditional_Unix_permissions
if (preg_match('#^[^/]([r-][w-][xstST-]){3}#', $longname)) {
switch ($longname[0]) {
case '-':
return NET_SFTP_TYPE_REGULAR;
case 'd':
return NET_SFTP_TYPE_DIRECTORY;
case 'l':
return NET_SFTP_TYPE_SYMLINK;
default:
return NET_SFTP_TYPE_SPECIAL;
}
}
return false;
}
/**
* Sends SFTP Packets
*
* See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info.
*
* @param int $type
* @param string $data
* @see self::_get_sftp_packet()
* @see Net_SSH2::_send_channel_packet()
* @return bool
* @access private
*/
function _send_sftp_packet($type, $data, $request_id = 1)
{
$packet = $this->use_request_id ?
pack('NCNa*', strlen($data) + 5, $type, $request_id, $data) :
pack('NCa*', strlen($data) + 1, $type, $data);
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
$result = $this->_send_channel_packet(NET_SFTP_CHANNEL, $packet);
$stop = strtok(microtime(), ' ') + strtok('');
if (defined('NET_SFTP_LOGGING')) {
$packet_type = '-> ' . $this->packet_types[$type] .
' (' . round($stop - $start, 4) . 's)';
if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
echo "\r\n" . $this->_format_log(array($data), array($packet_type)) . "\r\n \r\n";
flush();
ob_flush();
} else {
$this->packet_type_log[] = $packet_type;
if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
$this->packet_log[] = $data;
}
}
}
return $result;
}
/**
* Receives SFTP Packets
*
* See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info.
*
* Incidentally, the number of SSH_MSG_CHANNEL_DATA messages has no bearing on the number of SFTP packets present.
* There can be one SSH_MSG_CHANNEL_DATA messages containing two SFTP packets or there can be two SSH_MSG_CHANNEL_DATA
* messages containing one SFTP packet.
*
* @see self::_send_sftp_packet()
* @return string
* @access private
*/
function _get_sftp_packet($request_id = null)
{
if (isset($request_id) && isset($this->requestBuffer[$request_id])) {
$this->packet_type = $this->requestBuffer[$request_id]['packet_type'];
$temp = $this->requestBuffer[$request_id]['packet'];
unset($this->requestBuffer[$request_id]);
return $temp;
}
$this->curTimeout = false;
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
// SFTP packet length
while (strlen($this->packet_buffer) < 4) {
$temp = $this->_get_channel_packet(NET_SFTP_CHANNEL, true);
if (is_bool($temp)) {
$this->packet_type = false;
$this->packet_buffer = '';
return false;
}
$this->packet_buffer.= $temp;
}
if (strlen($this->packet_buffer) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($this->packet_buffer, 4)));
$tempLength = $length;
$tempLength-= strlen($this->packet_buffer);
// SFTP packet type and data payload
while ($tempLength > 0) {
$temp = $this->_get_channel_packet(NET_SFTP_CHANNEL, true);
if (is_bool($temp)) {
$this->packet_type = false;
$this->packet_buffer = '';
return false;
}
$this->packet_buffer.= $temp;
$tempLength-= strlen($temp);
}
$stop = strtok(microtime(), ' ') + strtok('');
$this->packet_type = ord($this->_string_shift($this->packet_buffer));
if ($this->use_request_id) {
extract(unpack('Npacket_id', $this->_string_shift($this->packet_buffer, 4))); // remove the request id
$length-= 5; // account for the request id and the packet type
} else {
$length-= 1; // account for the packet type
}
$packet = $this->_string_shift($this->packet_buffer, $length);
if (defined('NET_SFTP_LOGGING')) {
$packet_type = '<- ' . $this->packet_types[$this->packet_type] .
' (' . round($stop - $start, 4) . 's)';
if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
echo "\r\n" . $this->_format_log(array($packet), array($packet_type)) . "\r\n \r\n";
flush();
ob_flush();
} else {
$this->packet_type_log[] = $packet_type;
if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
$this->packet_log[] = $packet;
}
}
}
if (isset($request_id) && $this->use_request_id && $packet_id != $request_id) {
$this->requestBuffer[$packet_id] = array(
'packet_type' => $this->packet_type,
'packet' => $packet
);
return $this->_get_sftp_packet($request_id);
}
return $packet;
}
/**
* Returns a log of the packets that have been sent and received.
*
* Returns a string if NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX, an array if NET_SFTP_LOGGING == NET_SFTP_LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING')
*
* @access public
* @return string or Array
*/
function getSFTPLog()
{
if (!defined('NET_SFTP_LOGGING')) {
return false;
}
switch (NET_SFTP_LOGGING) {
case NET_SFTP_LOG_COMPLEX:
return $this->_format_log($this->packet_log, $this->packet_type_log);
break;
//case NET_SFTP_LOG_SIMPLE:
default:
return $this->packet_type_log;
}
}
/**
* Returns all errors
*
* @return array
* @access public
*/
function getSFTPErrors()
{
return $this->sftp_errors;
}
/**
* Returns the last error
*
* @return string
* @access public
*/
function getLastSFTPError()
{
return count($this->sftp_errors) ? $this->sftp_errors[count($this->sftp_errors) - 1] : '';
}
/**
* Get supported SFTP versions
*
* @return array
* @access public
*/
function getSupportedVersions()
{
$temp = array('version' => $this->version);
if (isset($this->extensions['versions'])) {
$temp['extensions'] = $this->extensions['versions'];
}
return $temp;
}
/**
* Disconnect
*
* @param int $reason
* @return bool
* @access private
*/
function _disconnect($reason)
{
$this->pwd = false;
parent::_disconnect($reason);
}
}
================================================
FILE: assets/libraries/phpseclib/Net/SSH1.php
================================================
* login('username', 'password')) {
* exit('Login Failed');
* }
*
* echo $ssh->exec('ls -la');
* ?>
*
*
* Here's another short example:
*
* login('username', 'password')) {
* exit('Login Failed');
* }
*
* echo $ssh->read('username@username:~$');
* $ssh->write("ls -la\n");
* echo $ssh->read('username@username:~$');
* ?>
*
*
* More information on the SSHv1 specification can be found by reading
* {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}.
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Net
* @package Net_SSH1
* @author Jim Wigginton
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**#@+
* Encryption Methods
*
* @see self::getSupportedCiphers()
* @access public
*/
/**
* No encryption
*
* Not supported.
*/
define('NET_SSH1_CIPHER_NONE', 0);
/**
* IDEA in CFB mode
*
* Not supported.
*/
define('NET_SSH1_CIPHER_IDEA', 1);
/**
* DES in CBC mode
*/
define('NET_SSH1_CIPHER_DES', 2);
/**
* Triple-DES in CBC mode
*
* All implementations are required to support this
*/
define('NET_SSH1_CIPHER_3DES', 3);
/**
* TRI's Simple Stream encryption CBC
*
* Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, does define it (see cipher.h),
* although it doesn't use it (see cipher.c)
*/
define('NET_SSH1_CIPHER_BROKEN_TSS', 4);
/**
* RC4
*
* Not supported.
*
* @internal According to the SSH1 specs:
*
* "The first 16 bytes of the session key are used as the key for
* the server to client direction. The remaining 16 bytes are used
* as the key for the client to server direction. This gives
* independent 128-bit keys for each direction."
*
* This library currently only supports encryption when the same key is being used for both directions. This is
* because there's only one $crypto object. Two could be added ($encrypt and $decrypt, perhaps).
*/
define('NET_SSH1_CIPHER_RC4', 5);
/**
* Blowfish
*
* Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, defines it (see cipher.h) and
* uses it (see cipher.c)
*/
define('NET_SSH1_CIPHER_BLOWFISH', 6);
/**#@-*/
/**#@+
* Authentication Methods
*
* @see self::getSupportedAuthentications()
* @access public
*/
/**
* .rhosts or /etc/hosts.equiv
*/
define('NET_SSH1_AUTH_RHOSTS', 1);
/**
* pure RSA authentication
*/
define('NET_SSH1_AUTH_RSA', 2);
/**
* password authentication
*
* This is the only method that is supported by this library.
*/
define('NET_SSH1_AUTH_PASSWORD', 3);
/**
* .rhosts with RSA host authentication
*/
define('NET_SSH1_AUTH_RHOSTS_RSA', 4);
/**#@-*/
/**#@+
* Terminal Modes
*
* @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html
* @access private
*/
define('NET_SSH1_TTY_OP_END', 0);
/**#@-*/
/**
* The Response Type
*
* @see self::_get_binary_packet()
* @access private
*/
define('NET_SSH1_RESPONSE_TYPE', 1);
/**
* The Response Data
*
* @see self::_get_binary_packet()
* @access private
*/
define('NET_SSH1_RESPONSE_DATA', 2);
/**#@+
* Execution Bitmap Masks
*
* @see self::bitmap
* @access private
*/
define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001);
define('NET_SSH1_MASK_CONNECTED', 0x00000002);
define('NET_SSH1_MASK_LOGIN', 0x00000004);
define('NET_SSH1_MASK_SHELL', 0x00000008);
/**#@-*/
/**#@+
* @access public
* @see self::getLog()
*/
/**
* Returns the message numbers
*/
define('NET_SSH1_LOG_SIMPLE', 1);
/**
* Returns the message content
*/
define('NET_SSH1_LOG_COMPLEX', 2);
/**
* Outputs the content real-time
*/
define('NET_SSH1_LOG_REALTIME', 3);
/**
* Dumps the content real-time to a file
*/
define('NET_SSH1_LOG_REALTIME_FILE', 4);
/**#@-*/
/**#@+
* @access public
* @see self::read()
*/
/**
* Returns when a string matching $expect exactly is found
*/
define('NET_SSH1_READ_SIMPLE', 1);
/**
* Returns when a string matching the regular expression $expect is found
*/
define('NET_SSH1_READ_REGEX', 2);
/**#@-*/
/**
* Pure-PHP implementation of SSHv1.
*
* @package Net_SSH1
* @author Jim Wigginton
* @access public
*/
class Net_SSH1
{
/**
* The SSH identifier
*
* @var string
* @access private
*/
var $identifier = 'SSH-1.5-phpseclib';
/**
* The Socket Object
*
* @var object
* @access private
*/
var $fsock;
/**
* The cryptography object
*
* @var object
* @access private
*/
var $crypto = false;
/**
* Execution Bitmap
*
* The bits that are set represent functions that have been called already. This is used to determine
* if a requisite function has been successfully executed. If not, an error should be thrown.
*
* @var int
* @access private
*/
var $bitmap = 0;
/**
* The Server Key Public Exponent
*
* Logged for debug purposes
*
* @see self::getServerKeyPublicExponent()
* @var string
* @access private
*/
var $server_key_public_exponent;
/**
* The Server Key Public Modulus
*
* Logged for debug purposes
*
* @see self::getServerKeyPublicModulus()
* @var string
* @access private
*/
var $server_key_public_modulus;
/**
* The Host Key Public Exponent
*
* Logged for debug purposes
*
* @see self::getHostKeyPublicExponent()
* @var string
* @access private
*/
var $host_key_public_exponent;
/**
* The Host Key Public Modulus
*
* Logged for debug purposes
*
* @see self::getHostKeyPublicModulus()
* @var string
* @access private
*/
var $host_key_public_modulus;
/**
* Supported Ciphers
*
* Logged for debug purposes
*
* @see self::getSupportedCiphers()
* @var array
* @access private
*/
var $supported_ciphers = array(
NET_SSH1_CIPHER_NONE => 'No encryption',
NET_SSH1_CIPHER_IDEA => 'IDEA in CFB mode',
NET_SSH1_CIPHER_DES => 'DES in CBC mode',
NET_SSH1_CIPHER_3DES => 'Triple-DES in CBC mode',
NET_SSH1_CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
NET_SSH1_CIPHER_RC4 => 'RC4',
NET_SSH1_CIPHER_BLOWFISH => 'Blowfish'
);
/**
* Supported Authentications
*
* Logged for debug purposes
*
* @see self::getSupportedAuthentications()
* @var array
* @access private
*/
var $supported_authentications = array(
NET_SSH1_AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv',
NET_SSH1_AUTH_RSA => 'pure RSA authentication',
NET_SSH1_AUTH_PASSWORD => 'password authentication',
NET_SSH1_AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication'
);
/**
* Server Identification
*
* @see self::getServerIdentification()
* @var string
* @access private
*/
var $server_identification = '';
/**
* Protocol Flags
*
* @see self::Net_SSH1()
* @var array
* @access private
*/
var $protocol_flags = array();
/**
* Protocol Flag Log
*
* @see self::getLog()
* @var array
* @access private
*/
var $protocol_flag_log = array();
/**
* Message Log
*
* @see self::getLog()
* @var array
* @access private
*/
var $message_log = array();
/**
* Real-time log file pointer
*
* @see self::_append_log()
* @var resource
* @access private
*/
var $realtime_log_file;
/**
* Real-time log file size
*
* @see self::_append_log()
* @var int
* @access private
*/
var $realtime_log_size;
/**
* Real-time log file wrap boolean
*
* @see self::_append_log()
* @var bool
* @access private
*/
var $realtime_log_wrap;
/**
* Interactive Buffer
*
* @see self::read()
* @var array
* @access private
*/
var $interactiveBuffer = '';
/**
* Timeout
*
* @see self::setTimeout()
* @access private
*/
var $timeout;
/**
* Current Timeout
*
* @see self::_get_channel_packet()
* @access private
*/
var $curTimeout;
/**
* Log Boundary
*
* @see self::_format_log()
* @access private
*/
var $log_boundary = ':';
/**
* Log Long Width
*
* @see self::_format_log()
* @access private
*/
var $log_long_width = 65;
/**
* Log Short Width
*
* @see self::_format_log()
* @access private
*/
var $log_short_width = 16;
/**
* Hostname
*
* @see self::Net_SSH1()
* @see self::_connect()
* @var string
* @access private
*/
var $host;
/**
* Port Number
*
* @see self::Net_SSH1()
* @see self::_connect()
* @var int
* @access private
*/
var $port;
/**
* Timeout for initial connection
*
* Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like
* exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor,
* however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be
* 10 seconds. It is used by fsockopen() in that function.
*
* @see self::Net_SSH1()
* @see self::_connect()
* @var int
* @access private
*/
var $connectionTimeout;
/**
* Default cipher
*
* @see self::Net_SSH1()
* @see self::_connect()
* @var int
* @access private
*/
var $cipher;
/**
* Default Constructor.
*
* Connects to an SSHv1 server
*
* @param string $host
* @param int $port
* @param int $timeout
* @param int $cipher
* @return Net_SSH1
* @access public
*/
function __construct($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
{
if (!class_exists('Math_BigInteger')) {
include_once 'Math/BigInteger.php';
}
// Include Crypt_Random
// the class_exists() will only be called if the crypt_random_string function hasn't been defined and
// will trigger a call to __autoload() if you're wanting to auto-load classes
// call function_exists() a second time to stop the include_once from being called outside
// of the auto loader
if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) {
include_once 'Crypt/Random.php';
}
$this->protocol_flags = array(
1 => 'NET_SSH1_MSG_DISCONNECT',
2 => 'NET_SSH1_SMSG_PUBLIC_KEY',
3 => 'NET_SSH1_CMSG_SESSION_KEY',
4 => 'NET_SSH1_CMSG_USER',
9 => 'NET_SSH1_CMSG_AUTH_PASSWORD',
10 => 'NET_SSH1_CMSG_REQUEST_PTY',
12 => 'NET_SSH1_CMSG_EXEC_SHELL',
13 => 'NET_SSH1_CMSG_EXEC_CMD',
14 => 'NET_SSH1_SMSG_SUCCESS',
15 => 'NET_SSH1_SMSG_FAILURE',
16 => 'NET_SSH1_CMSG_STDIN_DATA',
17 => 'NET_SSH1_SMSG_STDOUT_DATA',
18 => 'NET_SSH1_SMSG_STDERR_DATA',
19 => 'NET_SSH1_CMSG_EOF',
20 => 'NET_SSH1_SMSG_EXITSTATUS',
33 => 'NET_SSH1_CMSG_EXIT_CONFIRMATION'
);
$this->_define_array($this->protocol_flags);
$this->host = $host;
$this->port = $port;
$this->connectionTimeout = $timeout;
$this->cipher = $cipher;
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param string $host
* @param int $port
* @param int $timeout
* @param int $cipher
* @access public
*/
function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
{
$this->__construct($host, $port, $timeout, $cipher);
}
/**
* Connect to an SSHv1 server
*
* @return bool
* @access private
*/
function _connect()
{
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
if (!$this->fsock) {
user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
return false;
}
$this->server_identification = $init_line = fgets($this->fsock, 255);
if (defined('NET_SSH1_LOGGING')) {
$this->_append_log('<-', $this->server_identification);
$this->_append_log('->', $this->identifier . "\r\n");
}
if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
user_error('Can only connect to SSH servers');
return false;
}
if ($parts[1][0] != 1) {
user_error("Cannot connect to SSH $parts[1] servers");
return false;
}
fputs($this->fsock, $this->identifier."\r\n");
$response = $this->_get_binary_packet();
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
user_error('Expected SSH_SMSG_PUBLIC_KEY');
return false;
}
$anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8);
$this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
$server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->server_key_public_exponent = $server_key_public_exponent;
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
$server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->server_key_public_modulus = $server_key_public_modulus;
$this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
$host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->host_key_public_exponent = $host_key_public_exponent;
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 2) {
return false;
}
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
$host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
$this->host_key_public_modulus = $host_key_public_modulus;
$this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
// get a list of the supported ciphers
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
foreach ($this->supported_ciphers as $mask => $name) {
if (($supported_ciphers_mask & (1 << $mask)) == 0) {
unset($this->supported_ciphers[$mask]);
}
}
// get a list of the supported authentications
if (strlen($response[NET_SSH1_RESPONSE_DATA]) < 4) {
return false;
}
extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
foreach ($this->supported_authentications as $mask => $name) {
if (($supported_authentications_mask & (1 << $mask)) == 0) {
unset($this->supported_authentications[$mask]);
}
}
$session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));
$session_key = crypt_random_string(32);
$double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$server_key_public_exponent,
$server_key_public_modulus
)
);
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$host_key_public_exponent,
$host_key_public_modulus
)
);
} else {
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$host_key_public_exponent,
$host_key_public_modulus
)
);
$double_encrypted_session_key = $this->_rsa_crypt(
$double_encrypted_session_key,
array(
$server_key_public_exponent,
$server_key_public_modulus
)
);
}
$cipher = isset($this->supported_ciphers[$this->cipher]) ? $this->cipher : NET_SSH1_CIPHER_3DES;
$data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_SESSION_KEY');
return false;
}
switch ($cipher) {
//case NET_SSH1_CIPHER_NONE:
// $this->crypto = new Crypt_Null();
// break;
case NET_SSH1_CIPHER_DES:
if (!class_exists('Crypt_DES')) {
include_once 'Crypt/DES.php';
}
$this->crypto = new Crypt_DES();
$this->crypto->disablePadding();
$this->crypto->enableContinuousBuffer();
$this->crypto->setKey(substr($session_key, 0, 8));
break;
case NET_SSH1_CIPHER_3DES:
if (!class_exists('Crypt_TripleDES')) {
include_once 'Crypt/TripleDES.php';
}
$this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC);
$this->crypto->disablePadding();
$this->crypto->enableContinuousBuffer();
$this->crypto->setKey(substr($session_key, 0, 24));
break;
//case NET_SSH1_CIPHER_RC4:
// if (!class_exists('Crypt_RC4')) {
// include_once 'Crypt/RC4.php';
// }
// $this->crypto = new Crypt_RC4();
// $this->crypto->enableContinuousBuffer();
// $this->crypto->setKey(substr($session_key, 0, 16));
// break;
}
$response = $this->_get_binary_packet();
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
user_error('Expected SSH_SMSG_SUCCESS');
return false;
}
$this->bitmap = NET_SSH1_MASK_CONNECTED;
return true;
}
/**
* Login
*
* @param string $username
* @param string $password
* @return bool
* @access public
*/
function login($username, $password = '')
{
if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) {
$this->bitmap |= NET_SSH1_MASK_CONSTRUCTOR;
if (!$this->_connect()) {
return false;
}
}
if (!($this->bitmap & NET_SSH1_MASK_CONNECTED)) {
return false;
}
$data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_USER');
return false;
}
$response = $this->_get_binary_packet();
if ($response === true) {
return false;
}
if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
$this->bitmap |= NET_SSH1_MASK_LOGIN;
return true;
} elseif ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
return false;
}
$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_AUTH_PASSWORD');
return false;
}
// remove the username and password from the last logged packet
if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) {
$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen('password'), 'password');
$this->message_log[count($this->message_log) - 1] = $data;
}
$response = $this->_get_binary_packet();
if ($response === true) {
return false;
}
if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
$this->bitmap |= NET_SSH1_MASK_LOGIN;
return true;
} elseif ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
return false;
} else {
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
return false;
}
}
/**
* Set Timeout
*
* $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely. setTimeout() makes it so it'll timeout.
* Setting $timeout to false or 0 will mean there is no timeout.
*
* @param mixed $timeout
*/
function setTimeout($timeout)
{
$this->timeout = $this->curTimeout = $timeout;
}
/**
* Executes a command on a non-interactive shell, returns the output, and quits.
*
* An SSH1 server will close the connection after a command has been executed on a non-interactive shell. SSH2
* servers don't, however, this isn't an SSH2 client. The way this works, on the server, is by initiating a
* shell with the -s option, as discussed in the following links:
*
* {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html}
* {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html}
*
* To execute further commands, a new Net_SSH1 object will need to be created.
*
* Returns false on failure and the output, otherwise.
*
* @see self::interactiveRead()
* @see self::interactiveWrite()
* @param string $cmd
* @return mixed
* @access public
*/
function exec($cmd, $block = true)
{
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}
$data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_EXEC_CMD');
return false;
}
if (!$block) {
return true;
}
$output = '';
$response = $this->_get_binary_packet();
if ($response !== false) {
do {
$output.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
$response = $this->_get_binary_packet();
} while (is_array($response) && $response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
}
$data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
// i don't think it's really all that important if this packet gets sent or not.
$this->_send_binary_packet($data);
fclose($this->fsock);
// reset the execution bitmap - a new Net_SSH1 object needs to be created.
$this->bitmap = 0;
return $output;
}
/**
* Creates an interactive shell
*
* @see self::interactiveRead()
* @see self::interactiveWrite()
* @return bool
* @access private
*/
function _initShell()
{
// connect using the sample parameters in protocol-1.5.txt.
// according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
// terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell.
$data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_REQUEST_PTY');
return false;
}
$response = $this->_get_binary_packet();
if ($response === true) {
return false;
}
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
user_error('Expected SSH_SMSG_SUCCESS');
return false;
}
$data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_EXEC_SHELL');
return false;
}
$this->bitmap |= NET_SSH1_MASK_SHELL;
//stream_set_blocking($this->fsock, 0);
return true;
}
/**
* Inputs a command into an interactive shell.
*
* @see self::interactiveWrite()
* @param string $cmd
* @return bool
* @access public
*/
function write($cmd)
{
return $this->interactiveWrite($cmd);
}
/**
* Returns the output of an interactive shell when there's a match for $expect
*
* $expect can take the form of a string literal or, if $mode == NET_SSH1_READ_REGEX,
* a regular expression.
*
* @see self::write()
* @param string $expect
* @param int $mode
* @return bool
* @access public
*/
function read($expect, $mode = NET_SSH1_READ_SIMPLE)
{
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}
if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}
$match = $expect;
while (true) {
if ($mode == NET_SSH1_READ_REGEX) {
preg_match($expect, $this->interactiveBuffer, $matches);
$match = isset($matches[0]) ? $matches[0] : '';
}
$pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
if ($pos !== false) {
return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
}
$response = $this->_get_binary_packet();
if ($response === true) {
return $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer));
}
$this->interactiveBuffer.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
}
}
/**
* Inputs a command into an interactive shell.
*
* @see self::interactiveRead()
* @param string $cmd
* @return bool
* @access public
*/
function interactiveWrite($cmd)
{
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}
if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_STDIN');
return false;
}
return true;
}
/**
* Returns the output of an interactive shell when no more output is available.
*
* Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see stuff like
* "^[[00m", you're seeing ANSI escape codes. According to
* {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
* does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
* there's not going to be much recourse.
*
* @see self::interactiveRead()
* @return string
* @access public
*/
function interactiveRead()
{
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
}
if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}
$read = array($this->fsock);
$write = $except = null;
if (stream_select($read, $write, $except, 0)) {
$response = $this->_get_binary_packet();
return substr($response[NET_SSH1_RESPONSE_DATA], 4);
} else {
return '';
}
}
/**
* Disconnect
*
* @access public
*/
function disconnect()
{
$this->_disconnect();
}
/**
* Destructor.
*
* Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
* disconnect().
*
* @access public
*/
function __destruct()
{
$this->_disconnect();
}
/**
* Disconnect
*
* @param string $msg
* @access private
*/
function _disconnect($msg = 'Client Quit')
{
if ($this->bitmap) {
$data = pack('C', NET_SSH1_CMSG_EOF);
$this->_send_binary_packet($data);
/*
$response = $this->_get_binary_packet();
if ($response === true) {
$response = array(NET_SSH1_RESPONSE_TYPE => -1);
}
switch ($response[NET_SSH1_RESPONSE_TYPE]) {
case NET_SSH1_SMSG_EXITSTATUS:
$data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
break;
default:
$data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
}
*/
$data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
$this->_send_binary_packet($data);
fclose($this->fsock);
$this->bitmap = 0;
}
}
/**
* Gets Binary Packets
*
* See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
*
* Also, this function could be improved upon by adding detection for the following exploit:
* http://www.securiteam.com/securitynews/5LP042K3FY.html
*
* @see self::_send_binary_packet()
* @return array
* @access private
*/
function _get_binary_packet()
{
if (feof($this->fsock)) {
//user_error('connection closed prematurely');
return false;
}
if ($this->curTimeout) {
$read = array($this->fsock);
$write = $except = null;
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
$sec = floor($this->curTimeout);
$usec = 1000000 * ($this->curTimeout - $sec);
// on windows this returns a "Warning: Invalid CRT parameters detected" error
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
//$this->_disconnect('Timeout');
return true;
}
$elapsed = strtok(microtime(), ' ') + strtok('') - $start;
$this->curTimeout-= $elapsed;
}
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
$data = fread($this->fsock, 4);
if (strlen($data) < 4) {
return false;
}
$temp = unpack('Nlength', $data);
$padding_length = 8 - ($temp['length'] & 7);
$length = $temp['length'] + $padding_length;
$raw = '';
while ($length > 0) {
$temp = fread($this->fsock, $length);
$raw.= $temp;
$length-= strlen($temp);
}
$stop = strtok(microtime(), ' ') + strtok('');
if (strlen($raw) && $this->crypto !== false) {
$raw = $this->crypto->decrypt($raw);
}
$padding = substr($raw, 0, $padding_length);
$type = $raw[$padding_length];
$data = substr($raw, $padding_length + 1, -4);
if (strlen($raw) < 4) {
return false;
}
$temp = unpack('Ncrc', substr($raw, -4));
//if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
// user_error('Bad CRC in packet from server');
// return false;
//}
$type = ord($type);
if (defined('NET_SSH1_LOGGING')) {
$temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
$temp = '<- ' . $temp .
' (' . round($stop - $start, 4) . 's)';
$this->_append_log($temp, $data);
}
return array(
NET_SSH1_RESPONSE_TYPE => $type,
NET_SSH1_RESPONSE_DATA => $data
);
}
/**
* Sends Binary Packets
*
* Returns true on success, false on failure.
*
* @see self::_get_binary_packet()
* @param string $data
* @return bool
* @access private
*/
function _send_binary_packet($data)
{
if (feof($this->fsock)) {
//user_error('connection closed prematurely');
return false;
}
$length = strlen($data) + 4;
$padding = crypt_random_string(8 - ($length & 7));
$orig = $data;
$data = $padding . $data;
$data.= pack('N', $this->_crc($data));
if ($this->crypto !== false) {
$data = $this->crypto->encrypt($data);
}
$packet = pack('Na*', $length, $data);
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
$result = strlen($packet) == fputs($this->fsock, $packet);
$stop = strtok(microtime(), ' ') + strtok('');
if (defined('NET_SSH1_LOGGING')) {
$temp = isset($this->protocol_flags[ord($orig[0])]) ? $this->protocol_flags[ord($orig[0])] : 'UNKNOWN';
$temp = '-> ' . $temp .
' (' . round($stop - $start, 4) . 's)';
$this->_append_log($temp, $orig);
}
return $result;
}
/**
* Cyclic Redundancy Check (CRC)
*
* PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
* we've reimplemented it. A more detailed discussion of the differences can be found after
* $crc_lookup_table's initialization.
*
* @see self::_get_binary_packet()
* @see self::_send_binary_packet()
* @param string $data
* @return int
* @access private
*/
function _crc($data)
{
static $crc_lookup_table = array(
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
);
// For this function to yield the same output as PHP's crc32 function, $crc would have to be
// set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
$crc = 0x00000000;
$length = strlen($data);
for ($i=0; $i<$length; $i++) {
// We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
// be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example,
// yields 0xFF800000 - not 0x00800000. The following link elaborates:
// http://www.php.net/manual/en/language.operators.bitwise.php#57281
$crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
}
// In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
// 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
return $crc;
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
/**
* RSA Encrypt
*
* Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
* should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that
* calls this call modexp, instead, but I think this makes things clearer, maybe...
*
* @see self::Net_SSH1()
* @param Math_BigInteger $m
* @param array $key
* @return Math_BigInteger
* @access private
*/
function _rsa_crypt($m, $key)
{
/*
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$rsa = new Crypt_RSA();
$rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
return $rsa->encrypt($m);
*/
// To quote from protocol-1.5.txt:
// The most significant byte (which is only partial as the value must be
// less than the public modulus, which is never a power of two) is zero.
//
// The next byte contains the value 2 (which stands for public-key
// encrypted data in the PKCS standard [PKCS#1]). Then, there are non-
// zero random bytes to fill any unused space, a zero byte, and the data
// to be encrypted in the least significant bytes, the last byte of the
// data in the least significant byte.
// Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
// under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
$modulus = $key[1]->toBytes();
$length = strlen($modulus) - strlen($m) - 3;
$random = '';
while (strlen($random) != $length) {
$block = crypt_random_string($length - strlen($random));
$block = str_replace("\x00", '', $block);
$random.= $block;
}
$temp = chr(0) . chr(2) . $random . chr(0) . $m;
$m = new Math_BigInteger($temp, 256);
$m = $m->modPow($key[0], $key[1]);
return $m->toBytes();
}
/**
* Define Array
*
* Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
* named constants from it, using the value as the name of the constant and the index as the value of the constant.
* If any of the constants that would be defined already exists, none of the constants will be defined.
*
* @param array $array
* @access private
*/
function _define_array()
{
$args = func_get_args();
foreach ($args as $arg) {
foreach ($arg as $key => $value) {
if (!defined($value)) {
define($value, $key);
} else {
break 2;
}
}
}
}
/**
* Returns a log of the packets that have been sent and received.
*
* Returns a string if NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX, an array if NET_SSH1_LOGGING == NET_SSH1_LOG_SIMPLE and false if !defined('NET_SSH1_LOGGING')
*
* @access public
* @return array|false|string
*/
function getLog()
{
if (!defined('NET_SSH1_LOGGING')) {
return false;
}
switch (NET_SSH1_LOGGING) {
case NET_SSH1_LOG_SIMPLE:
return $this->message_number_log;
break;
case NET_SSH1_LOG_COMPLEX:
return $this->_format_log($this->message_log, $this->protocol_flags_log);
break;
default:
return false;
}
}
/**
* Formats a log for printing
*
* @param array $message_log
* @param array $message_number_log
* @access private
* @return string
*/
function _format_log($message_log, $message_number_log)
{
$output = '';
for ($i = 0; $i < count($message_log); $i++) {
$output.= $message_number_log[$i] . "\r\n";
$current_log = $message_log[$i];
$j = 0;
do {
if (strlen($current_log)) {
$output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 ';
}
$fragment = $this->_string_shift($current_log, $this->log_short_width);
$hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary));
// replace non ASCII printable characters with dots
// http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
// also replace < with a . since < messes up the output on web browsers
$raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
$output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
$j++;
} while (strlen($current_log));
$output.= "\r\n";
}
return $output;
}
/**
* Helper function for _format_log
*
* For use with preg_replace_callback()
*
* @param array $matches
* @access private
* @return string
*/
function _format_log_helper($matches)
{
return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
}
/**
* Return the server key public exponent
*
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
* the raw bytes. This behavior is similar to PHP's md5() function.
*
* @param bool $raw_output
* @return string
* @access public
*/
function getServerKeyPublicExponent($raw_output = false)
{
return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
}
/**
* Return the server key public modulus
*
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
* the raw bytes. This behavior is similar to PHP's md5() function.
*
* @param bool $raw_output
* @return string
* @access public
*/
function getServerKeyPublicModulus($raw_output = false)
{
return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
}
/**
* Return the host key public exponent
*
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
* the raw bytes. This behavior is similar to PHP's md5() function.
*
* @param bool $raw_output
* @return string
* @access public
*/
function getHostKeyPublicExponent($raw_output = false)
{
return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
}
/**
* Return the host key public modulus
*
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
* the raw bytes. This behavior is similar to PHP's md5() function.
*
* @param bool $raw_output
* @return string
* @access public
*/
function getHostKeyPublicModulus($raw_output = false)
{
return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
}
/**
* Return a list of ciphers supported by SSH1 server.
*
* Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
* is set to true, returns, instead, an array of constants. ie. instead of array('Triple-DES in CBC mode'), you'll
* get array(NET_SSH1_CIPHER_3DES).
*
* @param bool $raw_output
* @return array
* @access public
*/
function getSupportedCiphers($raw_output = false)
{
return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
}
/**
* Return a list of authentications supported by SSH1 server.
*
* Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
* is set to true, returns, instead, an array of constants. ie. instead of array('password authentication'), you'll
* get array(NET_SSH1_AUTH_PASSWORD).
*
* @param bool $raw_output
* @return array
* @access public
*/
function getSupportedAuthentications($raw_output = false)
{
return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
}
/**
* Return the server identification.
*
* @return string
* @access public
*/
function getServerIdentification()
{
return rtrim($this->server_identification);
}
/**
* Logs data packets
*
* Makes sure that only the last 1MB worth of packets will be logged
*
* @param string $data
* @access private
*/
function _append_log($protocol_flags, $message)
{
switch (NET_SSH1_LOGGING) {
// useful for benchmarks
case NET_SSH1_LOG_SIMPLE:
$this->protocol_flags_log[] = $protocol_flags;
break;
// the most useful log for SSH1
case NET_SSH1_LOG_COMPLEX:
$this->protocol_flags_log[] = $protocol_flags;
$this->_string_shift($message);
$this->log_size+= strlen($message);
$this->message_log[] = $message;
while ($this->log_size > NET_SSH1_LOG_MAX_SIZE) {
$this->log_size-= strlen(array_shift($this->message_log));
array_shift($this->protocol_flags_log);
}
break;
// dump the output out realtime; packets may be interspersed with non packets,
// passwords won't be filtered out and select other packets may not be correctly
// identified
case NET_SSH1_LOG_REALTIME:
echo "\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n \r\n";
@flush();
@ob_flush();
break;
// basically the same thing as NET_SSH1_LOG_REALTIME with the caveat that NET_SSH1_LOG_REALTIME_FILE
// needs to be defined and that the resultant log file will be capped out at NET_SSH1_LOG_MAX_SIZE.
// the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
// at the beginning of the file
case NET_SSH1_LOG_REALTIME_FILE:
if (!isset($this->realtime_log_file)) {
// PHP doesn't seem to like using constants in fopen()
$filename = NET_SSH1_LOG_REALTIME_FILE;
$fp = fopen($filename, 'w');
$this->realtime_log_file = $fp;
}
if (!is_resource($this->realtime_log_file)) {
break;
}
$entry = $this->_format_log(array($message), array($protocol_flags));
if ($this->realtime_log_wrap) {
$temp = "<<< START >>>\r\n";
$entry.= $temp;
fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
}
$this->realtime_log_size+= strlen($entry);
if ($this->realtime_log_size > NET_SSH1_LOG_MAX_SIZE) {
fseek($this->realtime_log_file, 0);
$this->realtime_log_size = strlen($entry);
$this->realtime_log_wrap = true;
}
fputs($this->realtime_log_file, $entry);
}
}
}
================================================
FILE: assets/libraries/phpseclib/Net/SSH2.php
================================================
* login('username', 'password')) {
* exit('Login Failed');
* }
*
* echo $ssh->exec('pwd');
* echo $ssh->exec('ls -la');
* ?>
*
*
*
* setPassword('whatever');
* $key->loadKey(file_get_contents('privatekey'));
*
* $ssh = new Net_SSH2('www.domain.tld');
* if (!$ssh->login('username', $key)) {
* exit('Login Failed');
* }
*
* echo $ssh->read('username@username:~$');
* $ssh->write("ls -la\n");
* echo $ssh->read('username@username:~$');
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category Net
* @package Net_SSH2
* @author Jim Wigginton
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
/**#@+
* Execution Bitmap Masks
*
* @see self::bitmap
* @access private
*/
define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001);
define('NET_SSH2_MASK_CONNECTED', 0x00000002);
define('NET_SSH2_MASK_LOGIN_REQ', 0x00000004);
define('NET_SSH2_MASK_LOGIN', 0x00000008);
define('NET_SSH2_MASK_SHELL', 0x00000010);
define('NET_SSH2_MASK_WINDOW_ADJUST', 0x00000020);
/**#@-*/
/**#@+
* Channel constants
*
* RFC4254 refers not to client and server channels but rather to sender and recipient channels. we don't refer
* to them in that way because RFC4254 toggles the meaning. the client sends a SSH_MSG_CHANNEL_OPEN message with
* a sender channel and the server sends a SSH_MSG_CHANNEL_OPEN_CONFIRMATION in response, with a sender and a
* recepient channel. at first glance, you might conclude that SSH_MSG_CHANNEL_OPEN_CONFIRMATION's sender channel
* would be the same thing as SSH_MSG_CHANNEL_OPEN's sender channel, but it's not, per this snipet:
* The 'recipient channel' is the channel number given in the original
* open request, and 'sender channel' is the channel number allocated by
* the other side.
*
* @see self::_send_channel_packet()
* @see self::_get_channel_packet()
* @access private
*/
define('NET_SSH2_CHANNEL_EXEC', 1); // PuTTy uses 0x100
define('NET_SSH2_CHANNEL_SHELL', 2);
define('NET_SSH2_CHANNEL_SUBSYSTEM', 3);
define('NET_SSH2_CHANNEL_AGENT_FORWARD', 4);
define('NET_SSH2_CHANNEL_KEEP_ALIVE', 5);
/**#@-*/
/**#@+
* @access public
* @see self::getLog()
*/
/**
* Returns the message numbers
*/
define('NET_SSH2_LOG_SIMPLE', 1);
/**
* Returns the message content
*/
define('NET_SSH2_LOG_COMPLEX', 2);
/**
* Outputs the content real-time
*/
define('NET_SSH2_LOG_REALTIME', 3);
/**
* Dumps the content real-time to a file
*/
define('NET_SSH2_LOG_REALTIME_FILE', 4);
/**
* Make sure that the log never gets larger than this
*/
define('NET_SSH2_LOG_MAX_SIZE', 1024 * 1024);
/**#@-*/
/**#@+
* @access public
* @see self::read()
*/
/**
* Returns when a string matching $expect exactly is found
*/
define('NET_SSH2_READ_SIMPLE', 1);
/**
* Returns when a string matching the regular expression $expect is found
*/
define('NET_SSH2_READ_REGEX', 2);
/**
* Returns when a string matching the regular expression $expect is found
*/
define('NET_SSH2_READ_NEXT', 3);
/**#@-*/
/**
* Pure-PHP implementation of SSHv2.
*
* @package Net_SSH2
* @author Jim Wigginton
* @access public
*/
class Net_SSH2
{
/**
* The SSH identifier
*
* @var string
* @access private
*/
var $identifier;
/**
* The Socket Object
*
* @var object
* @access private
*/
var $fsock;
/**
* Execution Bitmap
*
* The bits that are set represent functions that have been called already. This is used to determine
* if a requisite function has been successfully executed. If not, an error should be thrown.
*
* @var int
* @access private
*/
var $bitmap = 0;
/**
* Error information
*
* @see self::getErrors()
* @see self::getLastError()
* @var string
* @access private
*/
var $errors = array();
/**
* Server Identifier
*
* @see self::getServerIdentification()
* @var array|false
* @access private
*/
var $server_identifier = false;
/**
* Key Exchange Algorithms
*
* @see self::getKexAlgorithims()
* @var array|false
* @access private
*/
var $kex_algorithms = false;
/**
* Minimum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
*
* @see self::_key_exchange()
* @var int
* @access private
*/
var $kex_dh_group_size_min = 1536;
/**
* Preferred Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
*
* @see self::_key_exchange()
* @var int
* @access private
*/
var $kex_dh_group_size_preferred = 2048;
/**
* Maximum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
*
* @see self::_key_exchange()
* @var int
* @access private
*/
var $kex_dh_group_size_max = 4096;
/**
* Server Host Key Algorithms
*
* @see self::getServerHostKeyAlgorithms()
* @var array|false
* @access private
*/
var $server_host_key_algorithms = false;
/**
* Encryption Algorithms: Client to Server
*
* @see self::getEncryptionAlgorithmsClient2Server()
* @var array|false
* @access private
*/
var $encryption_algorithms_client_to_server = false;
/**
* Encryption Algorithms: Server to Client
*
* @see self::getEncryptionAlgorithmsServer2Client()
* @var array|false
* @access private
*/
var $encryption_algorithms_server_to_client = false;
/**
* MAC Algorithms: Client to Server
*
* @see self::getMACAlgorithmsClient2Server()
* @var array|false
* @access private
*/
var $mac_algorithms_client_to_server = false;
/**
* MAC Algorithms: Server to Client
*
* @see self::getMACAlgorithmsServer2Client()
* @var array|false
* @access private
*/
var $mac_algorithms_server_to_client = false;
/**
* Compression Algorithms: Client to Server
*
* @see self::getCompressionAlgorithmsClient2Server()
* @var array|false
* @access private
*/
var $compression_algorithms_client_to_server = false;
/**
* Compression Algorithms: Server to Client
*
* @see self::getCompressionAlgorithmsServer2Client()
* @var array|false
* @access private
*/
var $compression_algorithms_server_to_client = false;
/**
* Languages: Server to Client
*
* @see self::getLanguagesServer2Client()
* @var array|false
* @access private
*/
var $languages_server_to_client = false;
/**
* Languages: Client to Server
*
* @see self::getLanguagesClient2Server()
* @var array|false
* @access private
*/
var $languages_client_to_server = false;
/**
* Block Size for Server to Client Encryption
*
* "Note that the length of the concatenation of 'packet_length',
* 'padding_length', 'payload', and 'random padding' MUST be a multiple
* of the cipher block size or 8, whichever is larger. This constraint
* MUST be enforced, even when using stream ciphers."
*
* -- http://tools.ietf.org/html/rfc4253#section-6
*
* @see self::Net_SSH2()
* @see self::_send_binary_packet()
* @var int
* @access private
*/
var $encrypt_block_size = 8;
/**
* Block Size for Client to Server Encryption
*
* @see self::Net_SSH2()
* @see self::_get_binary_packet()
* @var int
* @access private
*/
var $decrypt_block_size = 8;
/**
* Server to Client Encryption Object
*
* @see self::_get_binary_packet()
* @var object
* @access private
*/
var $decrypt = false;
/**
* Client to Server Encryption Object
*
* @see self::_send_binary_packet()
* @var object
* @access private
*/
var $encrypt = false;
/**
* Client to Server HMAC Object
*
* @see self::_send_binary_packet()
* @var object
* @access private
*/
var $hmac_create = false;
/**
* Server to Client HMAC Object
*
* @see self::_get_binary_packet()
* @var object
* @access private
*/
var $hmac_check = false;
/**
* Size of server to client HMAC
*
* We need to know how big the HMAC will be for the server to client direction so that we know how many bytes to read.
* For the client to server side, the HMAC object will make the HMAC as long as it needs to be. All we need to do is
* append it.
*
* @see self::_get_binary_packet()
* @var int
* @access private
*/
var $hmac_size = false;
/**
* Server Public Host Key
*
* @see self::getServerPublicHostKey()
* @var string
* @access private
*/
var $server_public_host_key;
/**
* Session identifier
*
* "The exchange hash H from the first key exchange is additionally
* used as the session identifier, which is a unique identifier for
* this connection."
*
* -- http://tools.ietf.org/html/rfc4253#section-7.2
*
* @see self::_key_exchange()
* @var string
* @access private
*/
var $session_id = false;
/**
* Exchange hash
*
* The current exchange hash
*
* @see self::_key_exchange()
* @var string
* @access private
*/
var $exchange_hash = false;
/**
* Message Numbers
*
* @see self::Net_SSH2()
* @var array
* @access private
*/
var $message_numbers = array();
/**
* Disconnection Message 'reason codes' defined in RFC4253
*
* @see self::Net_SSH2()
* @var array
* @access private
*/
var $disconnect_reasons = array();
/**
* SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254
*
* @see self::Net_SSH2()
* @var array
* @access private
*/
var $channel_open_failure_reasons = array();
/**
* Terminal Modes
*
* @link http://tools.ietf.org/html/rfc4254#section-8
* @see self::Net_SSH2()
* @var array
* @access private
*/
var $terminal_modes = array();
/**
* SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes
*
* @link http://tools.ietf.org/html/rfc4254#section-5.2
* @see self::Net_SSH2()
* @var array
* @access private
*/
var $channel_extended_data_type_codes = array();
/**
* Send Sequence Number
*
* See 'Section 6.4. Data Integrity' of rfc4253 for more info.
*
* @see self::_send_binary_packet()
* @var int
* @access private
*/
var $send_seq_no = 0;
/**
* Get Sequence Number
*
* See 'Section 6.4. Data Integrity' of rfc4253 for more info.
*
* @see self::_get_binary_packet()
* @var int
* @access private
*/
var $get_seq_no = 0;
/**
* Server Channels
*
* Maps client channels to server channels
*
* @see self::_get_channel_packet()
* @see self::exec()
* @var array
* @access private
*/
var $server_channels = array();
/**
* Channel Buffers
*
* If a client requests a packet from one channel but receives two packets from another those packets should
* be placed in a buffer
*
* @see self::_get_channel_packet()
* @see self::exec()
* @var array
* @access private
*/
var $channel_buffers = array();
/**
* Channel Status
*
* Contains the type of the last sent message
*
* @see self::_get_channel_packet()
* @var array
* @access private
*/
var $channel_status = array();
/**
* Packet Size
*
* Maximum packet size indexed by channel
*
* @see self::_send_channel_packet()
* @var array
* @access private
*/
var $packet_size_client_to_server = array();
/**
* Message Number Log
*
* @see self::getLog()
* @var array
* @access private
*/
var $message_number_log = array();
/**
* Message Log
*
* @see self::getLog()
* @var array
* @access private
*/
var $message_log = array();
/**
* The Window Size
*
* Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 2GB)
*
* @var int
* @see self::_send_channel_packet()
* @see self::exec()
* @access private
*/
var $window_size = 0x7FFFFFFF;
/**
* Window size, server to client
*
* Window size indexed by channel
*
* @see self::_send_channel_packet()
* @var array
* @access private
*/
var $window_size_server_to_client = array();
/**
* Window size, client to server
*
* Window size indexed by channel
*
* @see self::_get_channel_packet()
* @var array
* @access private
*/
var $window_size_client_to_server = array();
/**
* Server signature
*
* Verified against $this->session_id
*
* @see self::getServerPublicHostKey()
* @var string
* @access private
*/
var $signature = '';
/**
* Server signature format
*
* ssh-rsa or ssh-dss.
*
* @see self::getServerPublicHostKey()
* @var string
* @access private
*/
var $signature_format = '';
/**
* Interactive Buffer
*
* @see self::read()
* @var array
* @access private
*/
var $interactiveBuffer = '';
/**
* Current log size
*
* Should never exceed NET_SSH2_LOG_MAX_SIZE
*
* @see self::_send_binary_packet()
* @see self::_get_binary_packet()
* @var int
* @access private
*/
var $log_size;
/**
* Timeout
*
* @see self::setTimeout()
* @access private
*/
var $timeout;
/**
* Current Timeout
*
* @see self::_get_channel_packet()
* @access private
*/
var $curTimeout;
/**
* Real-time log file pointer
*
* @see self::_append_log()
* @var resource
* @access private
*/
var $realtime_log_file;
/**
* Real-time log file size
*
* @see self::_append_log()
* @var int
* @access private
*/
var $realtime_log_size;
/**
* Has the signature been validated?
*
* @see self::getServerPublicHostKey()
* @var bool
* @access private
*/
var $signature_validated = false;
/**
* Real-time log file wrap boolean
*
* @see self::_append_log()
* @access private
*/
var $realtime_log_wrap;
/**
* Flag to suppress stderr from output
*
* @see self::enableQuietMode()
* @access private
*/
var $quiet_mode = false;
/**
* Time of first network activity
*
* @var int
* @access private
*/
var $last_packet;
/**
* Exit status returned from ssh if any
*
* @var int
* @access private
*/
var $exit_status;
/**
* Flag to request a PTY when using exec()
*
* @var bool
* @see self::enablePTY()
* @access private
*/
var $request_pty = false;
/**
* Flag set while exec() is running when using enablePTY()
*
* @var bool
* @access private
*/
var $in_request_pty_exec = false;
/**
* Flag set after startSubsystem() is called
*
* @var bool
* @access private
*/
var $in_subsystem;
/**
* Contents of stdError
*
* @var string
* @access private
*/
var $stdErrorLog;
/**
* The Last Interactive Response
*
* @see self::_keyboard_interactive_process()
* @var string
* @access private
*/
var $last_interactive_response = '';
/**
* Keyboard Interactive Request / Responses
*
* @see self::_keyboard_interactive_process()
* @var array
* @access private
*/
var $keyboard_requests_responses = array();
/**
* Banner Message
*
* Quoting from the RFC, "in some jurisdictions, sending a warning message before
* authentication may be relevant for getting legal protection."
*
* @see self::_filter()
* @see self::getBannerMessage()
* @var string
* @access private
*/
var $banner_message = '';
/**
* Did read() timeout or return normally?
*
* @see self::isTimeout()
* @var bool
* @access private
*/
var $is_timeout = false;
/**
* Log Boundary
*
* @see self::_format_log()
* @var string
* @access private
*/
var $log_boundary = ':';
/**
* Log Long Width
*
* @see self::_format_log()
* @var int
* @access private
*/
var $log_long_width = 65;
/**
* Log Short Width
*
* @see self::_format_log()
* @var int
* @access private
*/
var $log_short_width = 16;
/**
* Hostname
*
* @see self::Net_SSH2()
* @see self::_connect()
* @var string
* @access private
*/
var $host;
/**
* Port Number
*
* @see self::Net_SSH2()
* @see self::_connect()
* @var int
* @access private
*/
var $port;
/**
* Number of columns for terminal window size
*
* @see self::getWindowColumns()
* @see self::setWindowColumns()
* @see self::setWindowSize()
* @var int
* @access private
*/
var $windowColumns = 80;
/**
* Number of columns for terminal window size
*
* @see self::getWindowRows()
* @see self::setWindowRows()
* @see self::setWindowSize()
* @var int
* @access private
*/
var $windowRows = 24;
/**
* Crypto Engine
*
* @see self::setCryptoEngine()
* @see self::_key_exchange()
* @var int
* @access private
*/
var $crypto_engine = false;
/**
* A System_SSH_Agent for use in the SSH2 Agent Forwarding scenario
*
* @var System_SSH_Agent
* @access private
*/
var $agent;
/**
* Send the identification string first?
*
* @var bool
* @access private
*/
var $send_id_string_first = true;
/**
* Send the key exchange initiation packet first?
*
* @var bool
* @access private
*/
var $send_kex_first = true;
/**
* Some versions of OpenSSH incorrectly calculate the key size
*
* @var bool
* @access private
*/
var $bad_key_size_fix = false;
/**
* The selected decryption algorithm
*
* @var string
* @access private
*/
var $decrypt_algorithm = '';
/**
* Should we try to re-connect to re-establish keys?
*
* @var bool
* @access private
*/
var $retry_connect = false;
/**
* Binary Packet Buffer
*
* @var string|false
* @access private
*/
var $binary_packet_buffer = false;
/**
* Preferred Signature Format
*
* @var string|false
* @access private
*/
var $preferred_signature_format = false;
/**
* Authentication Credentials
*
* @var array
* @access private
*/
var $auth = array();
/**
* Default Constructor.
*
* $host can either be a string, representing the host, or a stream resource.
*
* @param mixed $host
* @param int $port
* @param int $timeout
* @see self::login()
* @return Net_SSH2
* @access public
*/
function __construct($host, $port = 22, $timeout = 10)
{
// Include Math_BigInteger
// Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
if (!class_exists('Math_BigInteger')) {
include_once 'Math/BigInteger.php';
}
if (!function_exists('crypt_random_string')) {
include_once 'Crypt/Random.php';
}
if (!class_exists('Crypt_Hash')) {
include_once 'Crypt/Hash.php';
}
// include Crypt_Base so constants can be defined for setCryptoEngine()
if (!class_exists('Crypt_Base')) {
include_once 'Crypt/Base.php';
}
$this->message_numbers = array(
1 => 'NET_SSH2_MSG_DISCONNECT',
2 => 'NET_SSH2_MSG_IGNORE',
3 => 'NET_SSH2_MSG_UNIMPLEMENTED',
4 => 'NET_SSH2_MSG_DEBUG',
5 => 'NET_SSH2_MSG_SERVICE_REQUEST',
6 => 'NET_SSH2_MSG_SERVICE_ACCEPT',
20 => 'NET_SSH2_MSG_KEXINIT',
21 => 'NET_SSH2_MSG_NEWKEYS',
30 => 'NET_SSH2_MSG_KEXDH_INIT',
31 => 'NET_SSH2_MSG_KEXDH_REPLY',
50 => 'NET_SSH2_MSG_USERAUTH_REQUEST',
51 => 'NET_SSH2_MSG_USERAUTH_FAILURE',
52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS',
53 => 'NET_SSH2_MSG_USERAUTH_BANNER',
80 => 'NET_SSH2_MSG_GLOBAL_REQUEST',
81 => 'NET_SSH2_MSG_REQUEST_SUCCESS',
82 => 'NET_SSH2_MSG_REQUEST_FAILURE',
90 => 'NET_SSH2_MSG_CHANNEL_OPEN',
91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION',
92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE',
93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST',
94 => 'NET_SSH2_MSG_CHANNEL_DATA',
95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA',
96 => 'NET_SSH2_MSG_CHANNEL_EOF',
97 => 'NET_SSH2_MSG_CHANNEL_CLOSE',
98 => 'NET_SSH2_MSG_CHANNEL_REQUEST',
99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS',
100 => 'NET_SSH2_MSG_CHANNEL_FAILURE'
);
$this->disconnect_reasons = array(
1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
4 => 'NET_SSH2_DISCONNECT_RESERVED',
5 => 'NET_SSH2_DISCONNECT_MAC_ERROR',
6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST',
11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION',
12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME'
);
$this->channel_open_failure_reasons = array(
1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED'
);
$this->terminal_modes = array(
0 => 'NET_SSH2_TTY_OP_END'
);
$this->channel_extended_data_type_codes = array(
1 => 'NET_SSH2_EXTENDED_DATA_STDERR'
);
$this->_define_array(
$this->message_numbers,
$this->disconnect_reasons,
$this->channel_open_failure_reasons,
$this->terminal_modes,
$this->channel_extended_data_type_codes,
array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'),
array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'),
array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE'),
// RFC 4419 - diffie-hellman-group-exchange-sha{1,256}
array(30 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST_OLD',
31 => 'NET_SSH2_MSG_KEXDH_GEX_GROUP',
32 => 'NET_SSH2_MSG_KEXDH_GEX_INIT',
33 => 'NET_SSH2_MSG_KEXDH_GEX_REPLY',
34 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST')
);
if (is_resource($host)) {
$this->fsock = $host;
return;
}
if (is_string($host)) {
$this->host = $host;
$this->port = $port;
$this->timeout = $timeout;
}
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param mixed $host
* @param int $port
* @param int $timeout
* @access public
*/
function Net_SSH2($host, $port = 22, $timeout = 10)
{
$this->__construct($host, $port, $timeout);
}
/**
* Set Crypto Engine Mode
*
* Possible $engine values:
* CRYPT_MODE_INTERNAL, CRYPT_MODE_MCRYPT
*
* @param int $engine
* @access public
*/
function setCryptoEngine($engine)
{
$this->crypto_engine = $engine;
}
/**
* Send Identification String First
*
* https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
* both sides MUST send an identification string". It does not say which side sends it first. In
* theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
*
* @access public
*/
function sendIdentificationStringFirst()
{
$this->send_id_string_first = true;
}
/**
* Send Identification String Last
*
* https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
* both sides MUST send an identification string". It does not say which side sends it first. In
* theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
*
* @access public
*/
function sendIdentificationStringLast()
{
$this->send_id_string_first = false;
}
/**
* Send SSH_MSG_KEXINIT First
*
* https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
* sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
* it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
*
* @access public
*/
function sendKEXINITFirst()
{
$this->send_kex_first = true;
}
/**
* Send SSH_MSG_KEXINIT Last
*
* https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
* sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
* it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
*
* @access public
*/
function sendKEXINITLast()
{
$this->send_kex_first = false;
}
/**
* Connect to an SSHv2 server
*
* @return bool
* @access private
*/
function _connect()
{
if ($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) {
return false;
}
$this->bitmap |= NET_SSH2_MASK_CONSTRUCTOR;
$this->curTimeout = $this->timeout;
$this->last_packet = strtok(microtime(), ' ') + strtok(''); // == microtime(true) in PHP5
if (!is_resource($this->fsock)) {
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
// with stream_select a timeout of 0 means that no timeout takes place;
// with fsockopen a timeout of 0 means that you instantly timeout
// to resolve this incompatibility a timeout of 100,000 will be used for fsockopen if timeout is 0
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout == 0 ? 100000 : $this->curTimeout);
if (!$this->fsock) {
$host = $this->host . ':' . $this->port;
user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
return false;
}
$elapsed = strtok(microtime(), ' ') + strtok('') - $start;
if ($this->curTimeout) {
$this->curTimeout-= $elapsed;
if ($this->curTimeout < 0) {
$this->is_timeout = true;
return false;
}
}
}
$this->identifier = $this->_generate_identifier();
if ($this->send_id_string_first) {
fputs($this->fsock, $this->identifier . "\r\n");
}
/* According to the SSH2 specs,
"The server MAY send other lines of data before sending the version
string. Each line SHOULD be terminated by a Carriage Return and Line
Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients
MUST be able to process such lines." */
$temp = '';
$extra = '';
while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) {
if (substr($temp, -2) == "\r\n") {
$extra.= $temp;
$temp = '';
}
if ($this->curTimeout) {
if ($this->curTimeout < 0) {
$this->is_timeout = true;
return false;
}
$read = array($this->fsock);
$write = $except = null;
$start = strtok(microtime(), ' ') + strtok('');
$sec = floor($this->curTimeout);
$usec = 1000000 * ($this->curTimeout - $sec);
// on windows this returns a "Warning: Invalid CRT parameters detected" error
// the !count() is done as a workaround for
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
$this->is_timeout = true;
return false;
}
$elapsed = strtok(microtime(), ' ') + strtok('') - $start;
$this->curTimeout-= $elapsed;
}
$temp.= fgets($this->fsock, 255);
}
if (feof($this->fsock)) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (defined('NET_SSH2_LOGGING')) {
$this->_append_log('<-', $extra . $temp);
$this->_append_log('->', $this->identifier . "\r\n");
}
$this->server_identifier = trim($temp, "\r\n");
if (strlen($extra)) {
$this->errors[] = $extra;
}
if (version_compare($matches[1], '1.99', '<')) {
user_error("Cannot connect to SSH $matches[1] servers");
return false;
}
if (!$this->send_id_string_first) {
fputs($this->fsock, $this->identifier . "\r\n");
}
if (!$this->send_kex_first) {
$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
user_error('Expected SSH_MSG_KEXINIT');
return false;
}
if (!$this->_key_exchange($response)) {
return false;
}
}
if ($this->send_kex_first && !$this->_key_exchange()) {
return false;
}
$this->bitmap|= NET_SSH2_MASK_CONNECTED;
return true;
}
/**
* Generates the SSH identifier
*
* You should overwrite this method in your own class if you want to use another identifier
*
* @access protected
* @return string
*/
function _generate_identifier()
{
$identifier = 'SSH-2.0-phpseclib_1.0';
$ext = array();
if (extension_loaded('openssl')) {
$ext[] = 'openssl';
} elseif (extension_loaded('mcrypt')) {
$ext[] = 'mcrypt';
}
if (extension_loaded('gmp')) {
$ext[] = 'gmp';
} elseif (extension_loaded('bcmath')) {
$ext[] = 'bcmath';
}
if (!empty($ext)) {
$identifier .= ' (' . implode(', ', $ext) . ')';
}
return $identifier;
}
/**
* Key Exchange
*
* @param string $kexinit_payload_server optional
* @access private
*/
function _key_exchange($kexinit_payload_server = false)
{
static $kex_algorithms = array(
'diffie-hellman-group1-sha1', // REQUIRED
'diffie-hellman-group14-sha1', // REQUIRED
'diffie-hellman-group-exchange-sha1', // RFC 4419
'diffie-hellman-group-exchange-sha256', // RFC 4419
);
static $server_host_key_algorithms = array(
'rsa-sha2-256', // RFC 8332
'rsa-sha2-512', // RFC 8332
'ssh-rsa', // RECOMMENDED sign Raw RSA Key
'ssh-dss' // REQUIRED sign Raw DSS Key
);
static $encryption_algorithms = false;
if ($encryption_algorithms === false) {
$encryption_algorithms = array(
// from :
'arcfour256',
'arcfour128',
//'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
// CTR modes from :
'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key
'aes192-ctr', // RECOMMENDED AES with 192-bit key
'aes256-ctr', // RECOMMENDED AES with 256-bit key
'twofish128-ctr', // OPTIONAL Twofish in SDCTR mode, with 128-bit key
'twofish192-ctr', // OPTIONAL Twofish with 192-bit key
'twofish256-ctr', // OPTIONAL Twofish with 256-bit key
'aes128-cbc', // RECOMMENDED AES with a 128-bit key
'aes192-cbc', // OPTIONAL AES with a 192-bit key
'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
'twofish128-cbc', // OPTIONAL Twofish with a 128-bit key
'twofish192-cbc', // OPTIONAL Twofish with a 192-bit key
'twofish256-cbc',
'twofish-cbc', // OPTIONAL alias for "twofish256-cbc"
// (this is being retained for historical reasons)
'blowfish-ctr', // OPTIONAL Blowfish in SDCTR mode
'blowfish-cbc', // OPTIONAL Blowfish in CBC mode
'3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode
'3des-cbc', // REQUIRED three-key 3DES in CBC mode
//'none' // OPTIONAL no encryption; NOT RECOMMENDED
);
if (extension_loaded('openssl') && !extension_loaded('mcrypt')) {
// OpenSSL does not support arcfour256 in any capacity and arcfour128 / arcfour support is limited to
// instances that do not use continuous buffers
$encryption_algorithms = array_diff(
$encryption_algorithms,
array('arcfour256', 'arcfour128', 'arcfour')
);
}
if (phpseclib_resolve_include_path('Crypt/RC4.php') === false) {
$encryption_algorithms = array_diff(
$encryption_algorithms,
array('arcfour256', 'arcfour128', 'arcfour')
);
}
if (phpseclib_resolve_include_path('Crypt/Rijndael.php') === false) {
$encryption_algorithms = array_diff(
$encryption_algorithms,
array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc')
);
}
if (phpseclib_resolve_include_path('Crypt/Twofish.php') === false) {
$encryption_algorithms = array_diff(
$encryption_algorithms,
array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc')
);
}
if (phpseclib_resolve_include_path('Crypt/Blowfish.php') === false) {
$encryption_algorithms = array_diff(
$encryption_algorithms,
array('blowfish-ctr', 'blowfish-cbc')
);
}
if (phpseclib_resolve_include_path('Crypt/TripleDES.php') === false) {
$encryption_algorithms = array_diff(
$encryption_algorithms,
array('3des-ctr', '3des-cbc')
);
}
$encryption_algorithms = array_values($encryption_algorithms);
}
$mac_algorithms = array(
// from :
'hmac-sha2-256',// RECOMMENDED HMAC-SHA256 (digest length = key length = 32)
'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20)
'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
//'none' // OPTIONAL no MAC; NOT RECOMMENDED
);
static $compression_algorithms = array(
'none' // REQUIRED no compression
//'zlib' // OPTIONAL ZLIB (LZ77) compression
);
// some SSH servers have buggy implementations of some of the above algorithms
switch (true) {
case $this->server_identifier == 'SSH-2.0-SSHD':
case substr($this->server_identifier, 0, 13) == 'SSH-2.0-DLINK':
$mac_algorithms = array_values(array_diff(
$mac_algorithms,
array('hmac-sha1-96', 'hmac-md5-96')
));
}
static $str_kex_algorithms, $str_server_host_key_algorithms,
$encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client,
$encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
if (empty($str_kex_algorithms)) {
$str_kex_algorithms = implode(',', $kex_algorithms);
$str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
$encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
$mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
$compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
}
$client_cookie = crypt_random_string(16);
$kexinit_payload_client = pack(
'Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
NET_SSH2_MSG_KEXINIT,
$client_cookie,
strlen($str_kex_algorithms),
$str_kex_algorithms,
strlen($str_server_host_key_algorithms),
$str_server_host_key_algorithms,
strlen($encryption_algorithms_client_to_server),
$encryption_algorithms_client_to_server,
strlen($encryption_algorithms_server_to_client),
$encryption_algorithms_server_to_client,
strlen($mac_algorithms_client_to_server),
$mac_algorithms_client_to_server,
strlen($mac_algorithms_server_to_client),
$mac_algorithms_server_to_client,
strlen($compression_algorithms_client_to_server),
$compression_algorithms_client_to_server,
strlen($compression_algorithms_server_to_client),
$compression_algorithms_server_to_client,
0,
'',
0,
'',
0,
0
);
if ($this->send_kex_first) {
if (!$this->_send_binary_packet($kexinit_payload_client)) {
return false;
}
$kexinit_payload_server = $this->_get_binary_packet();
if ($kexinit_payload_server === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) {
user_error('Expected SSH_MSG_KEXINIT');
return false;
}
}
$response = $kexinit_payload_server;
$this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
$server_cookie = $this->_string_shift($response, 16);
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
if (!strlen($response)) {
return false;
}
extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
$first_kex_packet_follows = $first_kex_packet_follows != 0;
if (!$this->send_kex_first && !$this->_send_binary_packet($kexinit_payload_client)) {
return false;
}
// we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
// we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
// diffie-hellman key exchange as fast as possible
$decrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_server_to_client);
$decryptKeyLength = $this->_encryption_algorithm_to_key_size($decrypt);
if ($decryptKeyLength === null) {
user_error('No compatible server to client encryption algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$encrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_client_to_server);
$encryptKeyLength = $this->_encryption_algorithm_to_key_size($encrypt);
if ($encryptKeyLength === null) {
user_error('No compatible client to server encryption algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength;
// through diffie-hellman key exchange a symmetric key is obtained
$kex_algorithm = $this->_array_intersect_first($kex_algorithms, $this->kex_algorithms);
if ($kex_algorithm === false) {
user_error('No compatible key exchange algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
if (strpos($kex_algorithm, 'diffie-hellman-group-exchange') === 0) {
$dh_group_sizes_packed = pack(
'NNN',
$this->kex_dh_group_size_min,
$this->kex_dh_group_size_preferred,
$this->kex_dh_group_size_max
);
$packet = pack(
'Ca*',
NET_SSH2_MSG_KEXDH_GEX_REQUEST,
$dh_group_sizes_packed
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != NET_SSH2_MSG_KEXDH_GEX_GROUP) {
user_error('Expected SSH_MSG_KEX_DH_GEX_GROUP');
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('NprimeLength', $this->_string_shift($response, 4)));
$primeBytes = $this->_string_shift($response, $primeLength);
$prime = new Math_BigInteger($primeBytes, -256);
if (strlen($response) < 4) {
return false;
}
extract(unpack('NgLength', $this->_string_shift($response, 4)));
$gBytes = $this->_string_shift($response, $gLength);
$g = new Math_BigInteger($gBytes, -256);
$exchange_hash_rfc4419 = pack(
'a*Na*Na*',
$dh_group_sizes_packed,
$primeLength,
$primeBytes,
$gLength,
$gBytes
);
$clientKexInitMessage = NET_SSH2_MSG_KEXDH_GEX_INIT;
$serverKexReplyMessage = NET_SSH2_MSG_KEXDH_GEX_REPLY;
} else {
switch ($kex_algorithm) {
// see http://tools.ietf.org/html/rfc2409#section-6.2 and
// http://tools.ietf.org/html/rfc2412, appendex E
case 'diffie-hellman-group1-sha1':
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
break;
// see http://tools.ietf.org/html/rfc3526#section-3
case 'diffie-hellman-group14-sha1':
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
'98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
'9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
'3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
break;
}
// For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1
// the generator field element is 2 (decimal) and the hash function is sha1.
$g = new Math_BigInteger(2);
$prime = new Math_BigInteger($prime, 16);
$exchange_hash_rfc4419 = '';
$clientKexInitMessage = NET_SSH2_MSG_KEXDH_INIT;
$serverKexReplyMessage = NET_SSH2_MSG_KEXDH_REPLY;
}
switch ($kex_algorithm) {
case 'diffie-hellman-group-exchange-sha256':
$kexHash = new Crypt_Hash('sha256');
break;
default:
$kexHash = new Crypt_Hash('sha1');
}
/* To increase the speed of the key exchange, both client and server may
reduce the size of their private exponents. It should be at least
twice as long as the key material that is generated from the shared
secret. For more details, see the paper by van Oorschot and Wiener
[VAN-OORSCHOT].
-- http://tools.ietf.org/html/rfc4419#section-6.2 */
$one = new Math_BigInteger(1);
$keyLength = min($keyLength, $kexHash->getLength());
$max = $one->bitwise_leftShift(16 * $keyLength); // 2 * 8 * $keyLength
$max = $max->subtract($one);
$x = $one->random($one, $max);
$e = $g->modPow($x, $prime);
$eBytes = $e->toBytes(true);
$data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
if (!$this->_send_binary_packet($data)) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != $serverKexReplyMessage) {
user_error('Expected SSH_MSG_KEXDH_REPLY');
return false;
}
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$fBytes = $this->_string_shift($response, $temp['length']);
$f = new Math_BigInteger($fBytes, -256);
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
$this->signature = $this->_string_shift($response, $temp['length']);
if (strlen($this->signature) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
$this->signature_format = $this->_string_shift($this->signature, $temp['length']);
$key = $f->modPow($x, $prime);
$keyBytes = $key->toBytes(true);
$this->exchange_hash = pack(
'Na*Na*Na*Na*Na*a*Na*Na*Na*',
strlen($this->identifier),
$this->identifier,
strlen($this->server_identifier),
$this->server_identifier,
strlen($kexinit_payload_client),
$kexinit_payload_client,
strlen($kexinit_payload_server),
$kexinit_payload_server,
strlen($this->server_public_host_key),
$this->server_public_host_key,
$exchange_hash_rfc4419,
strlen($eBytes),
$eBytes,
strlen($fBytes),
$fBytes,
strlen($keyBytes),
$keyBytes
);
$this->exchange_hash = $kexHash->hash($this->exchange_hash);
if ($this->session_id === false) {
$this->session_id = $this->exchange_hash;
}
$server_host_key_algorithm = $this->_array_intersect_first($server_host_key_algorithms, $this->server_host_key_algorithms);
if ($server_host_key_algorithm === false) {
user_error('No compatible server host key algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
switch ($server_host_key_algorithm) {
case 'ssh-dss':
$expected_key_format = 'ssh-dss';
break;
//case 'rsa-sha2-256':
//case 'rsa-sha2-512':
//case 'ssh-rsa':
default:
$expected_key_format = 'ssh-rsa';
}
if ($public_key_format != $expected_key_format || $this->signature_format != $server_host_key_algorithm) {
switch (true) {
case $this->signature_format == $server_host_key_algorithm:
case $server_host_key_algorithm != 'rsa-sha2-256' && $server_host_key_algorithm != 'rsa-sha2-512':
case $this->signature_format != 'ssh-rsa':
user_error('Server Host Key Algorithm Mismatch');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
}
$packet = pack(
'C',
NET_SSH2_MSG_NEWKEYS
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != NET_SSH2_MSG_NEWKEYS) {
user_error('Expected SSH_MSG_NEWKEYS');
return false;
}
switch ($encrypt) {
case '3des-cbc':
if (!class_exists('Crypt_TripleDES')) {
include_once 'Crypt/TripleDES.php';
}
$this->encrypt = new Crypt_TripleDES();
// $this->encrypt_block_size = 64 / 8 == the default
break;
case '3des-ctr':
if (!class_exists('Crypt_TripleDES')) {
include_once 'Crypt/TripleDES.php';
}
$this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
// $this->encrypt_block_size = 64 / 8 == the default
break;
case 'aes256-cbc':
case 'aes192-cbc':
case 'aes128-cbc':
if (!class_exists('Crypt_Rijndael')) {
include_once 'Crypt/Rijndael.php';
}
$this->encrypt = new Crypt_Rijndael();
$this->encrypt_block_size = 16; // eg. 128 / 8
break;
case 'aes256-ctr':
case 'aes192-ctr':
case 'aes128-ctr':
if (!class_exists('Crypt_Rijndael')) {
include_once 'Crypt/Rijndael.php';
}
$this->encrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR);
$this->encrypt_block_size = 16; // eg. 128 / 8
break;
case 'blowfish-cbc':
if (!class_exists('Crypt_Blowfish')) {
include_once 'Crypt/Blowfish.php';
}
$this->encrypt = new Crypt_Blowfish();
$this->encrypt_block_size = 8;
break;
case 'blowfish-ctr':
if (!class_exists('Crypt_Blowfish')) {
include_once 'Crypt/Blowfish.php';
}
$this->encrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
$this->encrypt_block_size = 8;
break;
case 'twofish128-cbc':
case 'twofish192-cbc':
case 'twofish256-cbc':
case 'twofish-cbc':
if (!class_exists('Crypt_Twofish')) {
include_once 'Crypt/Twofish.php';
}
$this->encrypt = new Crypt_Twofish();
$this->encrypt_block_size = 16;
break;
case 'twofish128-ctr':
case 'twofish192-ctr':
case 'twofish256-ctr':
if (!class_exists('Crypt_Twofish')) {
include_once 'Crypt/Twofish.php';
}
$this->encrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
$this->encrypt_block_size = 16;
break;
case 'arcfour':
case 'arcfour128':
case 'arcfour256':
if (!class_exists('Crypt_RC4')) {
include_once 'Crypt/RC4.php';
}
$this->encrypt = new Crypt_RC4();
break;
case 'none':
//$this->encrypt = new Crypt_Null();
}
switch ($decrypt) {
case '3des-cbc':
if (!class_exists('Crypt_TripleDES')) {
include_once 'Crypt/TripleDES.php';
}
$this->decrypt = new Crypt_TripleDES();
break;
case '3des-ctr':
if (!class_exists('Crypt_TripleDES')) {
include_once 'Crypt/TripleDES.php';
}
$this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
break;
case 'aes256-cbc':
case 'aes192-cbc':
case 'aes128-cbc':
if (!class_exists('Crypt_Rijndael')) {
include_once 'Crypt/Rijndael.php';
}
$this->decrypt = new Crypt_Rijndael();
$this->decrypt_block_size = 16;
break;
case 'aes256-ctr':
case 'aes192-ctr':
case 'aes128-ctr':
if (!class_exists('Crypt_Rijndael')) {
include_once 'Crypt/Rijndael.php';
}
$this->decrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR);
$this->decrypt_block_size = 16;
break;
case 'blowfish-cbc':
if (!class_exists('Crypt_Blowfish')) {
include_once 'Crypt/Blowfish.php';
}
$this->decrypt = new Crypt_Blowfish();
$this->decrypt_block_size = 8;
break;
case 'blowfish-ctr':
if (!class_exists('Crypt_Blowfish')) {
include_once 'Crypt/Blowfish.php';
}
$this->decrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
$this->decrypt_block_size = 8;
break;
case 'twofish128-cbc':
case 'twofish192-cbc':
case 'twofish256-cbc':
case 'twofish-cbc':
if (!class_exists('Crypt_Twofish')) {
include_once 'Crypt/Twofish.php';
}
$this->decrypt = new Crypt_Twofish();
$this->decrypt_block_size = 16;
break;
case 'twofish128-ctr':
case 'twofish192-ctr':
case 'twofish256-ctr':
if (!class_exists('Crypt_Twofish')) {
include_once 'Crypt/Twofish.php';
}
$this->decrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
$this->decrypt_block_size = 16;
break;
case 'arcfour':
case 'arcfour128':
case 'arcfour256':
if (!class_exists('Crypt_RC4')) {
include_once 'Crypt/RC4.php';
}
$this->decrypt = new Crypt_RC4();
break;
case 'none':
//$this->decrypt = new Crypt_Null();
}
$this->decrypt_algorithm = $decrypt;
$keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
if ($this->encrypt) {
if ($this->crypto_engine) {
$this->encrypt->setPreferredEngine($this->crypto_engine);
}
$this->encrypt->enableContinuousBuffer();
$this->encrypt->disablePadding();
$iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id);
while ($this->encrypt_block_size > strlen($iv)) {
$iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
}
$this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id);
while ($encryptKeyLength > strlen($key)) {
$key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
}
$this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
}
if ($this->decrypt) {
if ($this->crypto_engine) {
$this->decrypt->setPreferredEngine($this->crypto_engine);
}
$this->decrypt->enableContinuousBuffer();
$this->decrypt->disablePadding();
$iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id);
while ($this->decrypt_block_size > strlen($iv)) {
$iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
}
$this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id);
while ($decryptKeyLength > strlen($key)) {
$key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
}
$this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
}
/* The "arcfour128" algorithm is the RC4 cipher, as described in
[SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream
generated by the cipher MUST be discarded, and the first byte of the
first encrypted packet MUST be encrypted using the 1537th byte of
keystream.
-- http://tools.ietf.org/html/rfc4345#section-4 */
if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
$this->encrypt->encrypt(str_repeat("\0", 1536));
}
if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
$this->decrypt->decrypt(str_repeat("\0", 1536));
}
$mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_client_to_server);
if ($mac_algorithm === false) {
user_error('No compatible client to server message authentication algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$createKeyLength = 0; // ie. $mac_algorithm == 'none'
switch ($mac_algorithm) {
case 'hmac-sha2-256':
$this->hmac_create = new Crypt_Hash('sha256');
$createKeyLength = 32;
break;
case 'hmac-sha1':
$this->hmac_create = new Crypt_Hash('sha1');
$createKeyLength = 20;
break;
case 'hmac-sha1-96':
$this->hmac_create = new Crypt_Hash('sha1-96');
$createKeyLength = 20;
break;
case 'hmac-md5':
$this->hmac_create = new Crypt_Hash('md5');
$createKeyLength = 16;
break;
case 'hmac-md5-96':
$this->hmac_create = new Crypt_Hash('md5-96');
$createKeyLength = 16;
}
$mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_server_to_client);
if ($mac_algorithm === false) {
user_error('No compatible server to client message authentication algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$checkKeyLength = 0;
$this->hmac_size = 0;
switch ($mac_algorithm) {
case 'hmac-sha2-256':
$this->hmac_check = new Crypt_Hash('sha256');
$checkKeyLength = 32;
$this->hmac_size = 32;
break;
case 'hmac-sha1':
$this->hmac_check = new Crypt_Hash('sha1');
$checkKeyLength = 20;
$this->hmac_size = 20;
break;
case 'hmac-sha1-96':
$this->hmac_check = new Crypt_Hash('sha1-96');
$checkKeyLength = 20;
$this->hmac_size = 12;
break;
case 'hmac-md5':
$this->hmac_check = new Crypt_Hash('md5');
$checkKeyLength = 16;
$this->hmac_size = 16;
break;
case 'hmac-md5-96':
$this->hmac_check = new Crypt_Hash('md5-96');
$checkKeyLength = 16;
$this->hmac_size = 12;
}
$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id);
while ($createKeyLength > strlen($key)) {
$key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
}
$this->hmac_create->setKey(substr($key, 0, $createKeyLength));
$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id);
while ($checkKeyLength > strlen($key)) {
$key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
}
$this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
$compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_server_to_client);
if ($compression_algorithm === false) {
user_error('No compatible server to client compression algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$this->decompress = $compression_algorithm == 'zlib';
$compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_client_to_server);
if ($compression_algorithm === false) {
user_error('No compatible client to server compression algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$this->compress = $compression_algorithm == 'zlib';
return true;
}
/**
* Maps an encryption algorithm name to the number of key bytes.
*
* @param string $algorithm Name of the encryption algorithm
* @return int|null Number of bytes as an integer or null for unknown
* @access private
*/
function _encryption_algorithm_to_key_size($algorithm)
{
if ($this->bad_key_size_fix && $this->_bad_algorithm_candidate($algorithm)) {
return 16;
}
switch ($algorithm) {
case 'none':
return 0;
case 'aes128-cbc':
case 'aes128-ctr':
case 'arcfour':
case 'arcfour128':
case 'blowfish-cbc':
case 'blowfish-ctr':
case 'twofish128-cbc':
case 'twofish128-ctr':
return 16;
case '3des-cbc':
case '3des-ctr':
case 'aes192-cbc':
case 'aes192-ctr':
case 'twofish192-cbc':
case 'twofish192-ctr':
return 24;
case 'aes256-cbc':
case 'aes256-ctr':
case 'arcfour256':
case 'twofish-cbc':
case 'twofish256-cbc':
case 'twofish256-ctr':
return 32;
}
return null;
}
/**
* Tests whether or not proposed algorithm has a potential for issues
*
* @link https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ssh2-aesctr-openssh.html
* @link https://bugzilla.mindrot.org/show_bug.cgi?id=1291
* @param string $algorithm Name of the encryption algorithm
* @return bool
* @access private
*/
function _bad_algorithm_candidate($algorithm)
{
switch ($algorithm) {
case 'arcfour256':
case 'aes192-ctr':
case 'aes256-ctr':
return true;
}
return false;
}
/**
* Login
*
* The $password parameter can be a plaintext password, a Crypt_RSA object or an array
*
* @param string $username
* @param mixed $password
* @param mixed $...
* @return bool
* @see self::_login()
* @access public
*/
function login($username)
{
$args = func_get_args();
$this->auth[] = $args;
return call_user_func_array(array(&$this, '_login'), $args);
}
/**
* Login Helper
*
* @param string $username
* @param mixed $password
* @param mixed $...
* @return bool
* @see self::_login_helper()
* @access private
*/
function _login($username)
{
if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
if (!$this->_connect()) {
return false;
}
}
$args = array_slice(func_get_args(), 1);
if (empty($args)) {
return $this->_login_helper($username);
}
foreach ($args as $arg) {
if ($this->_login_helper($username, $arg)) {
return true;
}
}
return false;
}
/**
* Login Helper
*
* @param string $username
* @param string $password
* @return bool
* @access private
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
* by sending dummy SSH_MSG_IGNORE messages.
*/
function _login_helper($username, $password = null)
{
if (!($this->bitmap & NET_SSH2_MASK_CONNECTED)) {
return false;
}
if (!($this->bitmap & NET_SSH2_MASK_LOGIN_REQ)) {
$packet = pack(
'CNa*',
NET_SSH2_MSG_SERVICE_REQUEST,
strlen('ssh-userauth'),
'ssh-userauth'
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
if ($this->retry_connect) {
$this->retry_connect = false;
if (!$this->_connect()) {
return false;
}
return $this->_login_helper($username, $password);
}
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
user_error('Expected SSH_MSG_SERVICE_ACCEPT');
return false;
}
$this->bitmap |= NET_SSH2_MASK_LOGIN_REQ;
}
if (strlen($this->last_interactive_response)) {
return !is_string($password) && !is_array($password) ? false : $this->_keyboard_interactive_process($password);
}
// although PHP5's get_class() preserves the case, PHP4's does not
if (is_object($password)) {
switch (strtolower(get_class($password))) {
case 'crypt_rsa':
return $this->_privatekey_login($username, $password);
case 'system_ssh_agent':
return $this->_ssh_agent_login($username, $password);
}
}
if (is_array($password)) {
if ($this->_keyboard_interactive_login($username, $password)) {
$this->bitmap |= NET_SSH2_MASK_LOGIN;
return true;
}
return false;
}
if (!isset($password)) {
$packet = pack(
'CNa*Na*Na*',
NET_SSH2_MSG_USERAUTH_REQUEST,
strlen($username),
$username,
strlen('ssh-connection'),
'ssh-connection',
strlen('none'),
'none'
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
switch ($type) {
case NET_SSH2_MSG_USERAUTH_SUCCESS:
$this->bitmap |= NET_SSH2_MASK_LOGIN;
return true;
//case NET_SSH2_MSG_USERAUTH_FAILURE:
default:
return false;
}
}
$packet = pack(
'CNa*Na*Na*CNa*',
NET_SSH2_MSG_USERAUTH_REQUEST,
strlen($username),
$username,
strlen('ssh-connection'),
'ssh-connection',
strlen('password'),
'password',
0,
strlen($password),
$password
);
// remove the username and password from the logged packet
if (!defined('NET_SSH2_LOGGING')) {
$logged = null;
} else {
$logged = pack(
'CNa*Na*Na*CNa*',
NET_SSH2_MSG_USERAUTH_REQUEST,
strlen('username'),
'username',
strlen('ssh-connection'),
'ssh-connection',
strlen('password'),
'password',
0,
strlen('password'),
'password'
);
}
if (!$this->_send_binary_packet($packet, $logged)) {
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
switch ($type) {
case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed
if (defined('NET_SSH2_LOGGING')) {
$this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ';
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . $this->_string_shift($response, $length);
return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
case NET_SSH2_MSG_USERAUTH_FAILURE:
// can we use keyboard-interactive authentication? if not then either the login is bad or the server employees
// multi-factor authentication
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$auth_methods = explode(',', $this->_string_shift($response, $length));
if (!strlen($response)) {
return false;
}
extract(unpack('Cpartial_success', $this->_string_shift($response, 1)));
$partial_success = $partial_success != 0;
if (!$partial_success && in_array('keyboard-interactive', $auth_methods)) {
if ($this->_keyboard_interactive_login($username, $password)) {
$this->bitmap |= NET_SSH2_MASK_LOGIN;
return true;
}
return false;
}
return false;
case NET_SSH2_MSG_USERAUTH_SUCCESS:
$this->bitmap |= NET_SSH2_MASK_LOGIN;
return true;
}
return false;
}
/**
* Login via keyboard-interactive authentication
*
* See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details. This is not a full-featured keyboard-interactive authenticator.
*
* @param string $username
* @param string $password
* @return bool
* @access private
*/
function _keyboard_interactive_login($username, $password)
{
$packet = pack(
'CNa*Na*Na*Na*Na*',
NET_SSH2_MSG_USERAUTH_REQUEST,
strlen($username),
$username,
strlen('ssh-connection'),
'ssh-connection',
strlen('keyboard-interactive'),
'keyboard-interactive',
0,
'',
0,
''
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
return $this->_keyboard_interactive_process($password);
}
/**
* Handle the keyboard-interactive requests / responses.
*
* @param string $responses...
* @return bool
* @access private
*/
function _keyboard_interactive_process()
{
$responses = func_get_args();
if (strlen($this->last_interactive_response)) {
$response = $this->last_interactive_response;
} else {
$orig = $response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
switch ($type) {
case NET_SSH2_MSG_USERAUTH_INFO_REQUEST:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->_string_shift($response, $length); // name; may be empty
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->_string_shift($response, $length); // instruction; may be empty
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->_string_shift($response, $length); // language tag; may be empty
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nnum_prompts', $this->_string_shift($response, 4)));
for ($i = 0; $i < count($responses); $i++) {
if (is_array($responses[$i])) {
foreach ($responses[$i] as $key => $value) {
$this->keyboard_requests_responses[$key] = $value;
}
unset($responses[$i]);
}
}
$responses = array_values($responses);
if (isset($this->keyboard_requests_responses)) {
for ($i = 0; $i < $num_prompts; $i++) {
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
// prompt - ie. "Password: "; must not be empty
$prompt = $this->_string_shift($response, $length);
//$echo = $this->_string_shift($response) != chr(0);
foreach ($this->keyboard_requests_responses as $key => $value) {
if (substr($prompt, 0, strlen($key)) == $key) {
$responses[] = $value;
break;
}
}
}
}
// see http://tools.ietf.org/html/rfc4256#section-3.2
if (strlen($this->last_interactive_response)) {
$this->last_interactive_response = '';
} elseif (defined('NET_SSH2_LOGGING')) {
$this->message_number_log[count($this->message_number_log) - 1] = str_replace(
'UNKNOWN',
'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
$this->message_number_log[count($this->message_number_log) - 1]
);
}
if (!count($responses) && $num_prompts) {
$this->last_interactive_response = $orig;
return false;
}
/*
After obtaining the requested information from the user, the client
MUST respond with an SSH_MSG_USERAUTH_INFO_RESPONSE message.
*/
// see http://tools.ietf.org/html/rfc4256#section-3.4
$packet = $logged = pack('CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses));
for ($i = 0; $i < count($responses); $i++) {
$packet.= pack('Na*', strlen($responses[$i]), $responses[$i]);
$logged.= pack('Na*', strlen('dummy-answer'), 'dummy-answer');
}
if (!$this->_send_binary_packet($packet, $logged)) {
return false;
}
if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
$this->message_number_log[count($this->message_number_log) - 1] = str_replace(
'UNKNOWN',
'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE',
$this->message_number_log[count($this->message_number_log) - 1]
);
}
/*
After receiving the response, the server MUST send either an
SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another
SSH_MSG_USERAUTH_INFO_REQUEST message.
*/
// maybe phpseclib should force close the connection after x request / responses? unless something like that is done
// there could be an infinite loop of request / responses.
return $this->_keyboard_interactive_process();
case NET_SSH2_MSG_USERAUTH_SUCCESS:
return true;
case NET_SSH2_MSG_USERAUTH_FAILURE:
return false;
}
return false;
}
/**
* Login with an ssh-agent provided key
*
* @param string $username
* @param System_SSH_Agent $agent
* @return bool
* @access private
*/
function _ssh_agent_login($username, $agent)
{
$this->agent = $agent;
$keys = $agent->requestIdentities();
foreach ($keys as $key) {
if ($this->_privatekey_login($username, $key)) {
return true;
}
}
return false;
}
/**
* Login with an RSA private key
*
* @param string $username
* @param Crypt_RSA $password
* @return bool
* @access private
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
* by sending dummy SSH_MSG_IGNORE messages.
*/
function _privatekey_login($username, $privatekey)
{
// see http://tools.ietf.org/html/rfc4253#page-15
$publickey = $privatekey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW);
if ($publickey === false) {
return false;
}
$publickey = array(
'e' => $publickey['e']->toBytes(true),
'n' => $publickey['n']->toBytes(true)
);
$publickey = pack(
'Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($publickey['e']),
$publickey['e'],
strlen($publickey['n']),
$publickey['n']
);
switch ($this->signature_format) {
case 'rsa-sha2-512':
$hash = 'sha512';
$signatureType = 'rsa-sha2-512';
break;
case 'rsa-sha2-256':
$hash = 'sha256';
$signatureType = 'rsa-sha2-256';
break;
//case 'ssh-rsa':
default:
$hash = 'sha1';
$signatureType = 'ssh-rsa';
}
$part1 = pack(
'CNa*Na*Na*',
NET_SSH2_MSG_USERAUTH_REQUEST,
strlen($username),
$username,
strlen('ssh-connection'),
'ssh-connection',
strlen('publickey'),
'publickey'
);
$part2 = pack('Na*Na*', strlen($signatureType), $signatureType, strlen($publickey), $publickey);
$packet = $part1 . chr(0) . $part2;
if (!$this->_send_binary_packet($packet)) {
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
switch ($type) {
case NET_SSH2_MSG_USERAUTH_FAILURE:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length);
return false;
case NET_SSH2_MSG_USERAUTH_PK_OK:
// we'll just take it on faith that the public key blob and the public key algorithm name are as
// they should be
if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
$this->message_number_log[count($this->message_number_log) - 1] = str_replace(
'UNKNOWN',
'NET_SSH2_MSG_USERAUTH_PK_OK',
$this->message_number_log[count($this->message_number_log) - 1]
);
}
}
$packet = $part1 . chr(1) . $part2;
$privatekey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$privatekey->setHash($hash);
$signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet));
$signature = pack('Na*Na*', strlen($signatureType), $signatureType, strlen($signature), $signature);
$packet.= pack('Na*', strlen($signature), $signature);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
switch ($type) {
case NET_SSH2_MSG_USERAUTH_FAILURE:
// either the login is bad or the server employs multi-factor authentication
return false;
case NET_SSH2_MSG_USERAUTH_SUCCESS:
$this->bitmap |= NET_SSH2_MASK_LOGIN;
return true;
}
return false;
}
/**
* Set Timeout
*
* $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely. setTimeout() makes it so it'll timeout.
* Setting $timeout to false or 0 will mean there is no timeout.
*
* @param mixed $timeout
* @access public
*/
function setTimeout($timeout)
{
$this->timeout = $this->curTimeout = $timeout;
}
/**
* Get the output from stdError
*
* @access public
*/
function getStdError()
{
return $this->stdErrorLog;
}
/**
* Execute Command
*
* If $callback is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually.
* In all likelihood, this is not a feature you want to be taking advantage of.
*
* @param string $command
* @param Callback $callback
* @return string
* @access public
*/
function exec($command, $callback = null)
{
$this->curTimeout = $this->timeout;
$this->is_timeout = false;
$this->stdErrorLog = '';
if (!$this->isAuthenticated()) {
return false;
}
if ($this->in_request_pty_exec) {
user_error('If you want to run multiple exec()\'s you will need to disable (and re-enable if appropriate) a PTY for each one.');
return false;
}
// RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to
// be adjusted". 0x7FFFFFFF is, at 2GB, the max size. technically, it should probably be decremented, but,
// honestly, if you're transferring more than 2GB, you probably shouldn't be using phpseclib, anyway.
// see http://tools.ietf.org/html/rfc4254#section-5.2 for more info
$this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC] = $this->window_size;
// 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy
// uses 0x4000, that's what will be used here, as well.
$packet_size = 0x4000;
$packet = pack(
'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
NET_SSH2_CHANNEL_EXEC,
$this->window_size_server_to_client[NET_SSH2_CHANNEL_EXEC],
$packet_size
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN;
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC);
if ($response === false) {
return false;
}
if ($this->request_pty === true) {
$terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
$packet = pack(
'CNNa*CNa*N5a*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[NET_SSH2_CHANNEL_EXEC],
strlen('pty-req'),
'pty-req',
1,
strlen('vt100'),
'vt100',
$this->windowColumns,
$this->windowRows,
0,
0,
strlen($terminal_modes),
$terminal_modes
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($response)) {
return false;
}
list(, $type) = unpack('C', $this->_string_shift($response, 1));
switch ($type) {
case NET_SSH2_MSG_CHANNEL_SUCCESS:
break;
case NET_SSH2_MSG_CHANNEL_FAILURE:
default:
user_error('Unable to request pseudo-terminal');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
$this->in_request_pty_exec = true;
}
// sending a pty-req SSH_MSG_CHANNEL_REQUEST message is unnecessary and, in fact, in most cases, slows things
// down. the one place where it might be desirable is if you're doing something like Net_SSH2::exec('ping localhost &').
// with a pty-req SSH_MSG_CHANNEL_REQUEST, exec() will return immediately and the ping process will then
// then immediately terminate. without such a request exec() will loop indefinitely. the ping process won't end but
// neither will your script.
// although, in theory, the size of SSH_MSG_CHANNEL_REQUEST could exceed the maximum packet size established by
// SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the
// "maximum size of an individual data packet". ie. SSH_MSG_CHANNEL_DATA. RFC4254#section-5.2 corroborates.
$packet = pack(
'CNNa*CNa*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[NET_SSH2_CHANNEL_EXEC],
strlen('exec'),
'exec',
1,
strlen($command),
$command
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC);
if ($response === false) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA;
if ($callback === false || $this->in_request_pty_exec) {
return true;
}
$output = '';
while (true) {
$temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC);
switch (true) {
case $temp === true:
return is_callable($callback) ? true : $output;
case $temp === false:
return false;
default:
if (is_callable($callback)) {
if (call_user_func($callback, $temp) === true) {
$this->_close_channel(NET_SSH2_CHANNEL_EXEC);
return true;
}
} else {
$output.= $temp;
}
}
}
}
/**
* Creates an interactive shell
*
* @see self::read()
* @see self::write()
* @return bool
* @access private
*/
function _initShell()
{
if ($this->in_request_pty_exec === true) {
return true;
}
$this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL] = $this->window_size;
$packet_size = 0x4000;
$packet = pack(
'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
NET_SSH2_CHANNEL_SHELL,
$this->window_size_server_to_client[NET_SSH2_CHANNEL_SHELL],
$packet_size
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN;
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL);
if ($response === false) {
return false;
}
$terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
$packet = pack(
'CNNa*CNa*N5a*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[NET_SSH2_CHANNEL_SHELL],
strlen('pty-req'),
'pty-req',
1,
strlen('vt100'),
'vt100',
$this->windowColumns,
$this->windowRows,
0,
0,
strlen($terminal_modes),
$terminal_modes
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
if (!strlen($response)) {
return false;
}
list(, $type) = unpack('C', $this->_string_shift($response, 1));
switch ($type) {
case NET_SSH2_MSG_CHANNEL_SUCCESS:
// if a pty can't be opened maybe commands can still be executed
case NET_SSH2_MSG_CHANNEL_FAILURE:
break;
default:
user_error('Unable to request pseudo-terminal');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
$packet = pack(
'CNNa*C',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[NET_SSH2_CHANNEL_SHELL],
strlen('shell'),
'shell',
1
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST;
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL);
if ($response === false) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA;
$this->bitmap |= NET_SSH2_MASK_SHELL;
return true;
}
/**
* Return the channel to be used with read() / write()
*
* @see self::read()
* @see self::write()
* @return int
* @access public
*/
function _get_interactive_channel()
{
switch (true) {
case $this->in_subsystem:
return NET_SSH2_CHANNEL_SUBSYSTEM;
case $this->in_request_pty_exec:
return NET_SSH2_CHANNEL_EXEC;
default:
return NET_SSH2_CHANNEL_SHELL;
}
}
/**
* Return an available open channel
*
* @return int
* @access public
*/
function _get_open_channel()
{
$channel = NET_SSH2_CHANNEL_EXEC;
do {
if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_OPEN) {
return $channel;
}
} while ($channel++ < NET_SSH2_CHANNEL_SUBSYSTEM);
return false;
}
/**
* Returns the output of an interactive shell
*
* Returns when there's a match for $expect, which can take the form of a string literal or,
* if $mode == NET_SSH2_READ_REGEX, a regular expression.
*
* @see self::write()
* @param string $expect
* @param int $mode
* @return string
* @access public
*/
function read($expect = '', $mode = NET_SSH2_READ_SIMPLE)
{
$this->curTimeout = $this->timeout;
$this->is_timeout = false;
if (!$this->isAuthenticated()) {
user_error('Operation disallowed prior to login()');
return false;
}
if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}
$channel = $this->_get_interactive_channel();
if ($mode == NET_SSH2_READ_NEXT) {
return $this->_get_channel_packet($channel);
}
$match = $expect;
while (true) {
if ($mode == NET_SSH2_READ_REGEX) {
preg_match($expect, substr($this->interactiveBuffer, -1024), $matches);
$match = isset($matches[0]) ? $matches[0] : '';
}
$pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
if ($pos !== false) {
return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
}
$response = $this->_get_channel_packet($channel);
if (is_bool($response)) {
$this->in_request_pty_exec = false;
return $response ? $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer)) : false;
}
$this->interactiveBuffer.= $response;
}
}
/**
* Inputs a command into an interactive shell.
*
* @see self::read()
* @param string $cmd
* @return bool
* @access public
*/
function write($cmd)
{
if (!$this->isAuthenticated()) {
user_error('Operation disallowed prior to login()');
return false;
}
if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
}
return $this->_send_channel_packet($this->_get_interactive_channel(), $cmd);
}
/**
* Start a subsystem.
*
* Right now only one subsystem at a time is supported. To support multiple subsystem's stopSubsystem() could accept
* a string that contained the name of the subsystem, but at that point, only one subsystem of each type could be opened.
* To support multiple subsystem's of the same name maybe it'd be best if startSubsystem() generated a new channel id and
* returns that and then that that was passed into stopSubsystem() but that'll be saved for a future date and implemented
* if there's sufficient demand for such a feature.
*
* @see self::stopSubsystem()
* @param string $subsystem
* @return bool
* @access public
*/
function startSubsystem($subsystem)
{
$this->window_size_server_to_client[NET_SSH2_CHANNEL_SUBSYSTEM] = $this->window_size;
$packet = pack(
'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
NET_SSH2_CHANNEL_SUBSYSTEM,
$this->window_size,
0x4000
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_OPEN;
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SUBSYSTEM);
if ($response === false) {
return false;
}
$packet = pack(
'CNNa*CNa*',
NET_SSH2_MSG_CHANNEL_REQUEST,
$this->server_channels[NET_SSH2_CHANNEL_SUBSYSTEM],
strlen('subsystem'),
'subsystem',
1,
strlen($subsystem),
$subsystem
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST;
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SUBSYSTEM);
if ($response === false) {
return false;
}
$this->channel_status[NET_SSH2_CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_DATA;
$this->bitmap |= NET_SSH2_MASK_SHELL;
$this->in_subsystem = true;
return true;
}
/**
* Stops a subsystem.
*
* @see self::startSubsystem()
* @return bool
* @access public
*/
function stopSubsystem()
{
$this->in_subsystem = false;
$this->_close_channel(NET_SSH2_CHANNEL_SUBSYSTEM);
return true;
}
/**
* Closes a channel
*
* If read() timed out you might want to just close the channel and have it auto-restart on the next read() call
*
* @access public
*/
function reset()
{
$this->_close_channel($this->_get_interactive_channel());
}
/**
* Is timeout?
*
* Did exec() or read() return because they timed out or because they encountered the end?
*
* @access public
*/
function isTimeout()
{
return $this->is_timeout;
}
/**
* Disconnect
*
* @access public
*/
function disconnect()
{
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
fclose($this->realtime_log_file);
}
}
/**
* Destructor.
*
* Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
* disconnect().
*
* @access public
*/
function __destruct()
{
$this->disconnect();
}
/**
* Is the connection still active?
*
* @return bool
* @access public
*/
function isConnected()
{
return (bool) ($this->bitmap & NET_SSH2_MASK_CONNECTED);
}
/**
* Have you successfully been logged in?
*
* @return bool
* @access public
*/
function isAuthenticated()
{
return (bool) ($this->bitmap & NET_SSH2_MASK_LOGIN);
}
/**
* Pings a server connection, or tries to reconnect if the connection has gone down
*
* Inspired by http://php.net/manual/en/mysqli.ping.php
*
* @return bool
* @access public
*/
function ping()
{
if (!$this->isAuthenticated()) {
return false;
}
$this->window_size_server_to_client[NET_SSH2_CHANNEL_KEEP_ALIVE] = $this->window_size;
$packet_size = 0x4000;
$packet = pack(
'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
NET_SSH2_CHANNEL_KEEP_ALIVE,
$this->window_size_server_to_client[NET_SSH2_CHANNEL_KEEP_ALIVE],
$packet_size
);
if (!@$this->_send_binary_packet($packet)) {
return $this->_reconnect();
}
$this->channel_status[NET_SSH2_CHANNEL_KEEP_ALIVE] = NET_SSH2_MSG_CHANNEL_OPEN;
$response = @$this->_get_channel_packet(NET_SSH2_CHANNEL_KEEP_ALIVE);
if ($response !== false) {
$this->_close_channel(NET_SSH2_CHANNEL_KEEP_ALIVE);
return true;
}
return $this->_reconnect();
}
/**
* In situ reconnect method
*
* @return boolean
* @access private
*/
function _reconnect()
{
$this->_reset_connection(NET_SSH2_DISCONNECT_CONNECTION_LOST);
$this->retry_connect = true;
if (!$this->_connect()) {
return false;
}
foreach ($this->auth as $auth) {
$result = call_user_func_array(array(&$this, 'parent::login'), $auth);
}
return $result;
}
/**
* Resets a connection for re-use
*
* @param int $reason
* @access private
*/
function _reset_connection($reason)
{
$this->_disconnect($reason);
$this->decrypt = $this->encrypt = false;
$this->decrypt_block_size = $this->encrypt_block_size = 8;
$this->hmac_check = $this->hmac_create = false;
$this->hmac_size = false;
$this->session_id = false;
$this->retry_connect = true;
$this->get_seq_no = $this->send_seq_no = 0;
}
/**
* Gets Binary Packets
*
* See '6. Binary Packet Protocol' of rfc4253 for more info.
*
* @see self::_send_binary_packet()
* @return string
* @access private
*/
function _get_binary_packet($skip_channel_filter = false)
{
if (!is_resource($this->fsock) || feof($this->fsock)) {
$this->bitmap = 0;
user_error('Connection closed prematurely');
return false;
}
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
$raw = fread($this->fsock, $this->decrypt_block_size);
if (!strlen($raw)) {
return '';
}
if ($this->decrypt !== false) {
$raw = $this->decrypt->decrypt($raw);
}
if ($raw === false) {
user_error('Unable to decrypt content');
return false;
}
if (strlen($raw) < 5) {
return false;
}
extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));
$remaining_length = $packet_length + 4 - $this->decrypt_block_size;
// quoting ,
// "implementations SHOULD check that the packet length is reasonable"
// PuTTY uses 0x9000 as the actual max packet size and so to shall we
if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
if (!$this->bad_key_size_fix && $this->_bad_algorithm_candidate($this->decrypt_algorithm) && !($this->bitmap & NET_SSH2_MASK_LOGIN)) {
$this->bad_key_size_fix = true;
$this->_reset_connection(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
return false;
}
user_error('Invalid size');
return false;
}
$buffer = '';
while ($remaining_length > 0) {
$temp = fread($this->fsock, $remaining_length);
if ($temp === false || feof($this->fsock)) {
$this->bitmap = 0;
user_error('Error reading from socket');
return false;
}
$buffer.= $temp;
$remaining_length-= strlen($temp);
}
$stop = strtok(microtime(), ' ') + strtok('');
if (strlen($buffer)) {
$raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
}
$payload = $this->_string_shift($raw, $packet_length - $padding_length - 1);
$padding = $this->_string_shift($raw, $padding_length); // should leave $raw empty
if ($this->hmac_check !== false) {
$hmac = fread($this->fsock, $this->hmac_size);
if ($hmac === false || strlen($hmac) != $this->hmac_size) {
$this->bitmap = 0;
user_error('Error reading socket');
return false;
} elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
user_error('Invalid HMAC');
return false;
}
}
//if ($this->decompress) {
// $payload = gzinflate(substr($payload, 2));
//}
$this->get_seq_no++;
if (defined('NET_SSH2_LOGGING')) {
$current = strtok(microtime(), ' ') + strtok('');
$message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')';
$message_number = '<- ' . $message_number .
' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
$this->_append_log($message_number, $payload);
$this->last_packet = $current;
}
return $this->_filter($payload, $skip_channel_filter);
}
/**
* Filter Binary Packets
*
* Because some binary packets need to be ignored...
*
* @see self::_get_binary_packet()
* @return string
* @access private
*/
function _filter($payload, $skip_channel_filter)
{
switch (ord($payload[0])) {
case NET_SSH2_MSG_DISCONNECT:
$this->_string_shift($payload, 1);
if (strlen($payload) < 8) {
return false;
}
extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
$this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . $this->_string_shift($payload, $length);
$this->bitmap = 0;
return false;
case NET_SSH2_MSG_IGNORE:
$payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_DEBUG:
$this->_string_shift($payload, 2);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$this->errors[] = 'SSH_MSG_DEBUG: ' . $this->_string_shift($payload, $length);
$payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_UNIMPLEMENTED:
return false;
case NET_SSH2_MSG_KEXINIT:
if ($this->session_id !== false) {
$this->send_kex_first = false;
if (!$this->_key_exchange($payload)) {
$this->bitmap = 0;
return false;
}
$payload = $this->_get_binary_packet($skip_channel_filter);
}
}
// see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in
if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
$this->_string_shift($payload, 1);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$this->banner_message = $this->_string_shift($payload, $length);
$payload = $this->_get_binary_packet();
}
// only called when we've already logged in
if (($this->bitmap & NET_SSH2_MASK_CONNECTED) && $this->isAuthenticated()) {
switch (ord($payload[0])) {
case NET_SSH2_MSG_CHANNEL_DATA:
case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
case NET_SSH2_MSG_CHANNEL_REQUEST:
case NET_SSH2_MSG_CHANNEL_CLOSE:
case NET_SSH2_MSG_CHANNEL_EOF:
if (!$skip_channel_filter && !empty($this->server_channels)) {
$this->binary_packet_buffer = $payload;
$this->_get_channel_packet(true);
$payload = $this->_get_binary_packet();
}
break;
case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . $this->_string_shift($payload, $length);
if (!$this->_send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE))) {
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
$payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
$this->_string_shift($payload, 1);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$data = $this->_string_shift($payload, $length);
if (strlen($payload) < 4) {
return false;
}
extract(unpack('Nserver_channel', $this->_string_shift($payload, 4)));
switch ($data) {
case 'auth-agent':
case 'auth-agent@openssh.com':
if (isset($this->agent)) {
$new_channel = NET_SSH2_CHANNEL_AGENT_FORWARD;
if (strlen($payload) < 8) {
return false;
}
extract(unpack('Nremote_window_size', $this->_string_shift($payload, 4)));
extract(unpack('Nremote_maximum_packet_size', $this->_string_shift($payload, 4)));
$this->packet_size_client_to_server[$new_channel] = $remote_window_size;
$this->window_size_server_to_client[$new_channel] = $remote_maximum_packet_size;
$this->window_size_client_to_server[$new_channel] = $this->window_size;
$packet_size = 0x4000;
$packet = pack(
'CN4',
NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
$server_channel,
$new_channel,
$packet_size,
$packet_size
);
$this->server_channels[$new_channel] = $server_channel;
$this->channel_status[$new_channel] = NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION;
if (!$this->_send_binary_packet($packet)) {
return false;
}
}
break;
default:
$packet = pack(
'CN3a*Na*',
NET_SSH2_MSG_REQUEST_FAILURE,
$server_channel,
NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED,
0,
'',
0,
''
);
if (!$this->_send_binary_packet($packet)) {
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
}
$payload = $this->_get_binary_packet($skip_channel_filter);
break;
case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
$this->_string_shift($payload, 1);
if (strlen($payload) < 8) {
return false;
}
extract(unpack('Nchannel', $this->_string_shift($payload, 4)));
extract(unpack('Nwindow_size', $this->_string_shift($payload, 4)));
$this->window_size_client_to_server[$channel]+= $window_size;
$payload = ($this->bitmap & NET_SSH2_MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet($skip_channel_filter);
}
}
return $payload;
}
/**
* Enable Quiet Mode
*
* Suppress stderr from output
*
* @access public
*/
function enableQuietMode()
{
$this->quiet_mode = true;
}
/**
* Disable Quiet Mode
*
* Show stderr in output
*
* @access public
*/
function disableQuietMode()
{
$this->quiet_mode = false;
}
/**
* Returns whether Quiet Mode is enabled or not
*
* @see self::enableQuietMode()
* @see self::disableQuietMode()
*
* @access public
* @return bool
*/
function isQuietModeEnabled()
{
return $this->quiet_mode;
}
/**
* Enable request-pty when using exec()
*
* @access public
*/
function enablePTY()
{
$this->request_pty = true;
}
/**
* Disable request-pty when using exec()
*
* @access public
*/
function disablePTY()
{
if ($this->in_request_pty_exec) {
$this->_close_channel(NET_SSH2_CHANNEL_EXEC);
$this->in_request_pty_exec = false;
}
$this->request_pty = false;
}
/**
* Returns whether request-pty is enabled or not
*
* @see self::enablePTY()
* @see self::disablePTY()
*
* @access public
* @return bool
*/
function isPTYEnabled()
{
return $this->request_pty;
}
/**
* Gets channel data
*
* Returns the data as a string if it's available and false if not.
*
* @param $client_channel
* @return mixed
* @access private
*/
function _get_channel_packet($client_channel, $skip_extended = false)
{
if (!empty($this->channel_buffers[$client_channel])) {
return array_shift($this->channel_buffers[$client_channel]);
}
while (true) {
if ($this->binary_packet_buffer !== false) {
$response = $this->binary_packet_buffer;
$this->binary_packet_buffer = false;
} else {
$read = array($this->fsock);
$write = $except = null;
if (!$this->curTimeout) {
@stream_select($read, $write, $except, null);
} else {
if ($this->curTimeout < 0) {
$this->is_timeout = true;
return true;
}
$read = array($this->fsock);
$write = $except = null;
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
$sec = floor($this->curTimeout);
$usec = 1000000 * ($this->curTimeout - $sec);
// on windows this returns a "Warning: Invalid CRT parameters detected" error
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
$this->is_timeout = true;
return true;
}
$elapsed = strtok(microtime(), ' ') + strtok('') - $start;
$this->curTimeout-= $elapsed;
}
$response = $this->_get_binary_packet(true);
if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server');
return false;
}
}
if ($client_channel == -1 && $response === true) {
return true;
}
if (!strlen($response)) {
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if (strlen($response) < 4) {
return false;
}
if ($type == NET_SSH2_MSG_CHANNEL_OPEN) {
extract(unpack('Nlength', $this->_string_shift($response, 4)));
} else {
extract(unpack('Nchannel', $this->_string_shift($response, 4)));
}
// will not be setup yet on incoming channel open request
if (isset($channel) && isset($this->channel_status[$channel]) && isset($this->window_size_server_to_client[$channel])) {
$this->window_size_server_to_client[$channel]-= strlen($response);
// resize the window, if appropriate
if ($this->window_size_server_to_client[$channel] < 0) {
$packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_size);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$this->window_size_server_to_client[$channel]+= $this->window_size;
}
switch ($type) {
case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
/*
if ($client_channel == NET_SSH2_CHANNEL_EXEC) {
$this->_send_channel_packet($client_channel, chr(0));
}
*/
// currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
if (strlen($response) < 8) {
return false;
}
extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
$data = $this->_string_shift($response, $length);
$this->stdErrorLog.= $data;
if ($skip_extended || $this->quiet_mode) {
continue 2;
}
if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) {
return $data;
}
if (!isset($this->channel_buffers[$channel])) {
$this->channel_buffers[$channel] = array();
}
$this->channel_buffers[$channel][] = $data;
continue 2;
case NET_SSH2_MSG_CHANNEL_REQUEST:
if ($this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_CLOSE) {
continue 2;
}
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$value = $this->_string_shift($response, $length);
switch ($value) {
case 'exit-signal':
$this->_string_shift($response, 1);
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
$this->_string_shift($response, 1);
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
if ($length) {
$this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
}
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
$this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
continue 3;
case 'exit-status':
if (strlen($response) < 5) {
return false;
}
extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5)));
$this->exit_status = $exit_status;
// "The client MAY ignore these messages."
// -- http://tools.ietf.org/html/rfc4254#section-6.10
continue 3;
default:
// "Some systems may not implement signals, in which case they SHOULD ignore this message."
// -- http://tools.ietf.org/html/rfc4254#section-6.9
continue 3;
}
}
switch ($this->channel_status[$channel]) {
case NET_SSH2_MSG_CHANNEL_OPEN:
switch ($type) {
case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nserver_channel', $this->_string_shift($response, 4)));
$this->server_channels[$channel] = $server_channel;
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nwindow_size', $this->_string_shift($response, 4)));
if ($window_size < 0) {
$window_size&= 0x7FFFFFFF;
$window_size+= 0x80000000;
}
$this->window_size_client_to_server[$channel] = $window_size;
if (strlen($response) < 4) {
return false;
}
$temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4));
$this->packet_size_client_to_server[$channel] = $temp['packet_size_client_to_server'];
$result = $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended);
$this->_on_channel_open();
return $result;
//case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
default:
user_error('Unable to open channel');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
break;
case NET_SSH2_MSG_CHANNEL_REQUEST:
switch ($type) {
case NET_SSH2_MSG_CHANNEL_SUCCESS:
return true;
case NET_SSH2_MSG_CHANNEL_FAILURE:
return false;
default:
user_error('Unable to fulfill channel request');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
case NET_SSH2_MSG_CHANNEL_CLOSE:
return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->_get_channel_packet($client_channel, $skip_extended);
}
}
// ie. $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA
switch ($type) {
case NET_SSH2_MSG_CHANNEL_DATA:
/*
if ($channel == NET_SSH2_CHANNEL_EXEC) {
// SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server
// this actually seems to make things twice as fast. more to the point, the message right after
// SSH_MSG_CHANNEL_DATA (usually SSH_MSG_IGNORE) won't block for as long as it would have otherwise.
// in OpenSSH it slows things down but only by a couple thousandths of a second.
$this->_send_channel_packet($channel, chr(0));
}
*/
if (strlen($response) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$data = $this->_string_shift($response, $length);
if ($channel == NET_SSH2_CHANNEL_AGENT_FORWARD) {
$agent_response = $this->agent->_forward_data($data);
if (!is_bool($agent_response)) {
$this->_send_channel_packet($channel, $agent_response);
}
break;
}
if ($client_channel == $channel) {
return $data;
}
if (!isset($this->channel_buffers[$channel])) {
$this->channel_buffers[$channel] = array();
}
$this->channel_buffers[$channel][] = $data;
break;
case NET_SSH2_MSG_CHANNEL_CLOSE:
$this->curTimeout = 0;
if ($this->bitmap & NET_SSH2_MASK_SHELL) {
$this->bitmap&= ~NET_SSH2_MASK_SHELL;
}
if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) {
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
}
$this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
if ($client_channel == $channel) {
return true;
}
case NET_SSH2_MSG_CHANNEL_EOF:
break;
default:
user_error('Error reading channel data');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
}
}
}
/**
* Sends Binary Packets
*
* See '6. Binary Packet Protocol' of rfc4253 for more info.
*
* @param string $data
* @param string $logged
* @see self::_get_binary_packet()
* @return bool
* @access private
*/
function _send_binary_packet($data, $logged = null)
{
if (!is_resource($this->fsock) || feof($this->fsock)) {
$this->bitmap = 0;
user_error('Connection closed prematurely');
return false;
}
//if ($this->compress) {
// // the -4 removes the checksum:
// // http://php.net/function.gzcompress#57710
// $data = substr(gzcompress($data), 0, -4);
//}
// 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9
$packet_length = strlen($data) + 9;
// round up to the nearest $this->encrypt_block_size
$packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size;
// subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length
$padding_length = $packet_length - strlen($data) - 5;
$padding = crypt_random_string($padding_length);
// we subtract 4 from packet_length because the packet_length field isn't supposed to include itself
$packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding);
$hmac = $this->hmac_create !== false ? $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet)) : '';
$this->send_seq_no++;
if ($this->encrypt !== false) {
$packet = $this->encrypt->encrypt($packet);
}
$packet.= $hmac;
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
$result = strlen($packet) == fputs($this->fsock, $packet);
$stop = strtok(microtime(), ' ') + strtok('');
if (defined('NET_SSH2_LOGGING')) {
$current = strtok(microtime(), ' ') + strtok('');
$message_number = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')';
$message_number = '-> ' . $message_number .
' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
$this->_append_log($message_number, isset($logged) ? $logged : $data);
$this->last_packet = $current;
}
return $result;
}
/**
* Logs data packets
*
* Makes sure that only the last 1MB worth of packets will be logged
*
* @param string $data
* @access private
*/
function _append_log($message_number, $message)
{
// remove the byte identifying the message type from all but the first two messages (ie. the identification strings)
if (strlen($message_number) > 2) {
$this->_string_shift($message);
}
switch (NET_SSH2_LOGGING) {
// useful for benchmarks
case NET_SSH2_LOG_SIMPLE:
$this->message_number_log[] = $message_number;
break;
// the most useful log for SSH2
case NET_SSH2_LOG_COMPLEX:
$this->message_number_log[] = $message_number;
$this->log_size+= strlen($message);
$this->message_log[] = $message;
while ($this->log_size > NET_SSH2_LOG_MAX_SIZE) {
$this->log_size-= strlen(array_shift($this->message_log));
array_shift($this->message_number_log);
}
break;
// dump the output out realtime; packets may be interspersed with non packets,
// passwords won't be filtered out and select other packets may not be correctly
// identified
case NET_SSH2_LOG_REALTIME:
switch (PHP_SAPI) {
case 'cli':
$start = $stop = "\r\n";
break;
default:
$start = '';
$stop = ' ';
}
echo $start . $this->_format_log(array($message), array($message_number)) . $stop;
@flush();
@ob_flush();
break;
// basically the same thing as NET_SSH2_LOG_REALTIME with the caveat that NET_SSH2_LOG_REALTIME_FILE
// needs to be defined and that the resultant log file will be capped out at NET_SSH2_LOG_MAX_SIZE.
// the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
// at the beginning of the file
case NET_SSH2_LOG_REALTIME_FILE:
if (!isset($this->realtime_log_file)) {
// PHP doesn't seem to like using constants in fopen()
$filename = NET_SSH2_LOG_REALTIME_FILENAME;
$fp = fopen($filename, 'w');
$this->realtime_log_file = $fp;
}
if (!is_resource($this->realtime_log_file)) {
break;
}
$entry = $this->_format_log(array($message), array($message_number));
if ($this->realtime_log_wrap) {
$temp = "<<< START >>>\r\n";
$entry.= $temp;
fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
}
$this->realtime_log_size+= strlen($entry);
if ($this->realtime_log_size > NET_SSH2_LOG_MAX_SIZE) {
fseek($this->realtime_log_file, 0);
$this->realtime_log_size = strlen($entry);
$this->realtime_log_wrap = true;
}
fputs($this->realtime_log_file, $entry);
}
}
/**
* Sends channel data
*
* Spans multiple SSH_MSG_CHANNEL_DATAs if appropriate
*
* @param int $client_channel
* @param string $data
* @return bool
* @access private
*/
function _send_channel_packet($client_channel, $data)
{
while (strlen($data)) {
if (!$this->window_size_client_to_server[$client_channel]) {
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
// using an invalid channel will let the buffers be built up for the valid channels
$this->_get_channel_packet(-1);
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
}
/* The maximum amount of data allowed is determined by the maximum
packet size for the channel, and the current window size, whichever
is smaller.
-- http://tools.ietf.org/html/rfc4254#section-5.2 */
$max_size = min(
$this->packet_size_client_to_server[$client_channel],
$this->window_size_client_to_server[$client_channel]
);
$temp = $this->_string_shift($data, $max_size);
$packet = pack(
'CN2a*',
NET_SSH2_MSG_CHANNEL_DATA,
$this->server_channels[$client_channel],
strlen($temp),
$temp
);
$this->window_size_client_to_server[$client_channel]-= strlen($temp);
if (!$this->_send_binary_packet($packet)) {
return false;
}
}
return true;
}
/**
* Closes and flushes a channel
*
* Net_SSH2 doesn't properly close most channels. For exec() channels are normally closed by the server
* and for SFTP channels are presumably closed when the client disconnects. This functions is intended
* for SCP more than anything.
*
* @param int $client_channel
* @param bool $want_reply
* @return bool
* @access private
*/
function _close_channel($client_channel, $want_reply = false)
{
// see http://tools.ietf.org/html/rfc4254#section-5.3
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
if (!$want_reply) {
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel]));
}
$this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
$this->curTimeout = 0;
while (!is_bool($this->_get_channel_packet($client_channel))) {
}
if ($want_reply) {
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel]));
}
if ($this->bitmap & NET_SSH2_MASK_SHELL) {
$this->bitmap&= ~NET_SSH2_MASK_SHELL;
}
}
/**
* Disconnect
*
* @param int $reason
* @return bool
* @access private
*/
function _disconnect($reason)
{
if ($this->bitmap & NET_SSH2_MASK_CONNECTED) {
$data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, '');
$this->_send_binary_packet($data);
$this->bitmap = 0;
fclose($this->fsock);
return false;
}
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
/**
* Define Array
*
* Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
* named constants from it, using the value as the name of the constant and the index as the value of the constant.
* If any of the constants that would be defined already exists, none of the constants will be defined.
*
* @param array $array
* @access private
*/
function _define_array()
{
$args = func_get_args();
foreach ($args as $arg) {
foreach ($arg as $key => $value) {
if (!defined($value)) {
define($value, $key);
} else {
break 2;
}
}
}
}
/**
* Returns a log of the packets that have been sent and received.
*
* Returns a string if NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX, an array if NET_SSH2_LOGGING == NET_SSH2_LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING')
*
* @access public
* @return array|false|string
*/
function getLog()
{
if (!defined('NET_SSH2_LOGGING')) {
return false;
}
switch (NET_SSH2_LOGGING) {
case NET_SSH2_LOG_SIMPLE:
return $this->message_number_log;
case NET_SSH2_LOG_COMPLEX:
$log = $this->_format_log($this->message_log, $this->message_number_log);
return PHP_SAPI == 'cli' ? $log : '' . $log . ' ';
default:
return false;
}
}
/**
* Formats a log for printing
*
* @param array $message_log
* @param array $message_number_log
* @access private
* @return string
*/
function _format_log($message_log, $message_number_log)
{
$output = '';
for ($i = 0; $i < count($message_log); $i++) {
$output.= $message_number_log[$i] . "\r\n";
$current_log = $message_log[$i];
$j = 0;
do {
if (strlen($current_log)) {
$output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 ';
}
$fragment = $this->_string_shift($current_log, $this->log_short_width);
$hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary));
// replace non ASCII printable characters with dots
// http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
// also replace < with a . since < messes up the output on web browsers
$raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
$output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
$j++;
} while (strlen($current_log));
$output.= "\r\n";
}
return $output;
}
/**
* Helper function for _format_log
*
* For use with preg_replace_callback()
*
* @param array $matches
* @access private
* @return string
*/
function _format_log_helper($matches)
{
return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
}
/**
* Helper function for agent->_on_channel_open()
*
* Used when channels are created to inform agent
* of said channel opening. Must be called after
* channel open confirmation received
*
* @access private
*/
function _on_channel_open()
{
if (isset($this->agent)) {
$this->agent->_on_channel_open($this);
}
}
/**
* Returns the first value of the intersection of two arrays or false if
* the intersection is empty. The order is defined by the first parameter.
*
* @param array $array1
* @param array $array2
* @return mixed False if intersection is empty, else intersected value.
* @access private
*/
function _array_intersect_first($array1, $array2)
{
foreach ($array1 as $value) {
if (in_array($value, $array2)) {
return $value;
}
}
return false;
}
/**
* Returns all errors
*
* @return string[]
* @access public
*/
function getErrors()
{
return $this->errors;
}
/**
* Returns the last error
*
* @return string
* @access public
*/
function getLastError()
{
$count = count($this->errors);
if ($count > 0) {
return $this->errors[$count - 1];
}
}
/**
* Return the server identification.
*
* @return string
* @access public
*/
function getServerIdentification()
{
$this->_connect();
return $this->server_identifier;
}
/**
* Return a list of the key exchange algorithms the server supports.
*
* @return array
* @access public
*/
function getKexAlgorithms()
{
$this->_connect();
return $this->kex_algorithms;
}
/**
* Return a list of the host key (public key) algorithms the server supports.
*
* @return array
* @access public
*/
function getServerHostKeyAlgorithms()
{
$this->_connect();
return $this->server_host_key_algorithms;
}
/**
* Return a list of the (symmetric key) encryption algorithms the server supports, when receiving stuff from the client.
*
* @return array
* @access public
*/
function getEncryptionAlgorithmsClient2Server()
{
$this->_connect();
return $this->encryption_algorithms_client_to_server;
}
/**
* Return a list of the (symmetric key) encryption algorithms the server supports, when sending stuff to the client.
*
* @return array
* @access public
*/
function getEncryptionAlgorithmsServer2Client()
{
$this->_connect();
return $this->encryption_algorithms_server_to_client;
}
/**
* Return a list of the MAC algorithms the server supports, when receiving stuff from the client.
*
* @return array
* @access public
*/
function getMACAlgorithmsClient2Server()
{
$this->_connect();
return $this->mac_algorithms_client_to_server;
}
/**
* Return a list of the MAC algorithms the server supports, when sending stuff to the client.
*
* @return array
* @access public
*/
function getMACAlgorithmsServer2Client()
{
$this->_connect();
return $this->mac_algorithms_server_to_client;
}
/**
* Return a list of the compression algorithms the server supports, when receiving stuff from the client.
*
* @return array
* @access public
*/
function getCompressionAlgorithmsClient2Server()
{
$this->_connect();
return $this->compression_algorithms_client_to_server;
}
/**
* Return a list of the compression algorithms the server supports, when sending stuff to the client.
*
* @return array
* @access public
*/
function getCompressionAlgorithmsServer2Client()
{
$this->_connect();
return $this->compression_algorithms_server_to_client;
}
/**
* Return a list of the languages the server supports, when sending stuff to the client.
*
* @return array
* @access public
*/
function getLanguagesServer2Client()
{
$this->_connect();
return $this->languages_server_to_client;
}
/**
* Return a list of the languages the server supports, when receiving stuff from the client.
*
* @return array
* @access public
*/
function getLanguagesClient2Server()
{
$this->_connect();
return $this->languages_client_to_server;
}
/**
* Returns the banner message.
*
* Quoting from the RFC, "in some jurisdictions, sending a warning message before
* authentication may be relevant for getting legal protection."
*
* @return string
* @access public
*/
function getBannerMessage()
{
return $this->banner_message;
}
/**
* Returns the server public host key.
*
* Caching this the first time you connect to a server and checking the result on subsequent connections
* is recommended. Returns false if the server signature is not signed correctly with the public host key.
*
* @return mixed
* @access public
*/
function getServerPublicHostKey()
{
if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
if (!$this->_connect()) {
return false;
}
}
$signature = $this->signature;
$server_public_host_key = $this->server_public_host_key;
if (strlen($server_public_host_key) < 4) {
return false;
}
extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4)));
$this->_string_shift($server_public_host_key, $length);
if ($this->signature_validated) {
return $this->bitmap ?
$this->signature_format . ' ' . base64_encode($this->server_public_host_key) :
false;
}
$this->signature_validated = true;
switch ($this->signature_format) {
case 'ssh-dss':
$zero = new Math_BigInteger();
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
/* The value for 'dss_signature_blob' is encoded as a string containing
r, followed by s (which are 160-bit integers, without lengths or
padding, unsigned, and in network byte order). */
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
if ($temp['length'] != 40) {
user_error('Invalid signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$r = new Math_BigInteger($this->_string_shift($signature, 20), 256);
$s = new Math_BigInteger($this->_string_shift($signature, 20), 256);
switch (true) {
case $r->equals($zero):
case $r->compare($q) >= 0:
case $s->equals($zero):
case $s->compare($q) >= 0:
user_error('Invalid signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$w = $s->modInverse($q);
$u1 = $w->multiply(new Math_BigInteger(sha1($this->exchange_hash), 16));
list(, $u1) = $u1->divide($q);
$u2 = $w->multiply($r);
list(, $u2) = $u2->divide($q);
$g = $g->modPow($u1, $p);
$y = $y->modPow($u2, $p);
$v = $g->multiply($y);
list(, $v) = $v->divide($p);
list(, $v) = $v->divide($q);
if (!$v->equals($r)) {
user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
break;
case 'ssh-rsa':
case 'rsa-sha2-256':
case 'rsa-sha2-512':
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
if (strlen($server_public_host_key) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$rawN = $this->_string_shift($server_public_host_key, $temp['length']);
$n = new Math_BigInteger($rawN, -256);
$nLength = strlen(ltrim($rawN, "\0"));
/*
if (strlen($signature) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
$signature = $this->_string_shift($signature, $temp['length']);
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$rsa = new Crypt_RSA();
switch ($this->signature_format) {
case 'rsa-sha2-512':
$hash = 'sha512';
break;
case 'rsa-sha2-256':
$hash = 'sha256';
break;
//case 'ssh-rsa':
default:
$hash = 'sha1';
}
$rsa->setHash($hash);
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW);
if (!$rsa->verify($this->exchange_hash, $signature)) {
user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
*/
if (strlen($signature) < 4) {
return false;
}
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
$s = new Math_BigInteger($this->_string_shift($signature, $temp['length']), 256);
// validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the
// following URL:
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
// also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) {
user_error('Invalid signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
$s = $s->modPow($e, $n);
$s = $s->toBytes();
switch ($this->signature_format) {
case 'rsa-sha2-512':
$hash = 'sha512';
break;
case 'rsa-sha2-256':
$hash = 'sha256';
break;
//case 'ssh-rsa':
default:
$hash = 'sha1';
}
$hashObj = new Crypt_Hash($hash);
switch ($this->signature_format) {
case 'rsa-sha2-512':
$h = pack('N5a*', 0x00305130, 0x0D060960, 0x86480165, 0x03040203, 0x05000440, $hashObj->hash($this->exchange_hash));
break;
case 'rsa-sha2-256':
$h = pack('N5a*', 0x00303130, 0x0D060960, 0x86480165, 0x03040201, 0x05000420, $hashObj->hash($this->exchange_hash));
break;
//case 'ssh-rsa':
default:
$hash = 'sha1';
$h = pack('N4a*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, $hashObj->hash($this->exchange_hash));
}
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
if ($s != $h) {
user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
break;
default:
user_error('Unsupported signature format');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
return $this->signature_format . ' ' . base64_encode($this->server_public_host_key);
}
/**
* Returns the exit status of an SSH command or false.
*
* @return false|int
* @access public
*/
function getExitStatus()
{
if (is_null($this->exit_status)) {
return false;
}
return $this->exit_status;
}
/**
* Returns the number of columns for the terminal window size.
*
* @return int
* @access public
*/
function getWindowColumns()
{
return $this->windowColumns;
}
/**
* Returns the number of rows for the terminal window size.
*
* @return int
* @access public
*/
function getWindowRows()
{
return $this->windowRows;
}
/**
* Sets the number of columns for the terminal window size.
*
* @param int $value
* @access public
*/
function setWindowColumns($value)
{
$this->windowColumns = $value;
}
/**
* Sets the number of rows for the terminal window size.
*
* @param int $value
* @access public
*/
function setWindowRows($value)
{
$this->windowRows = $value;
}
/**
* Sets the number of columns and rows for the terminal window size.
*
* @param int $columns
* @param int $rows
* @access public
*/
function setWindowSize($columns = 80, $rows = 24)
{
$this->windowColumns = $columns;
$this->windowRows = $rows;
}
}
================================================
FILE: assets/libraries/phpseclib/System/SSH/Agent.php
================================================
* login('username', $agent)) {
* exit('Login Failed');
* }
*
* echo $ssh->exec('pwd');
* echo $ssh->exec('ls -la');
* ?>
*
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category System
* @package System_SSH_Agent
* @author Jim Wigginton
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
* @internal See http://api.libssh.org/rfc/PROTOCOL.agent
*/
/**#@+
* Message numbers
*
* @access private
*/
// to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1)
define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11);
// this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2).
define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12);
define('SYSTEM_SSH_AGENT_FAILURE', 5);
// the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3)
define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
// the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
/**#@-*/
/**@+
* Agent forwarding status
*
* @access private
*/
// no forwarding requested and not active
define('SYSTEM_SSH_AGENT_FORWARD_NONE', 0);
// request agent forwarding when opportune
define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1);
// forwarding has been request and is active
define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2);
/**#@-*/
/**@+
* Signature Flags
*
* See https://tools.ietf.org/html/draft-miller-ssh-agent-00#section-5.3
*
* @access private
*/
define('SYSTEM_SSH_AGENT_RSA2_256', 2);
define('SYSTEM_SSH_AGENT_RSA2_512', 4);
/**#@-*/
/**
* Pure-PHP ssh-agent client identity object
*
* Instantiation should only be performed by System_SSH_Agent class.
* This could be thought of as implementing an interface that Crypt_RSA
* implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
* The methods in this interface would be getPublicKey, setSignatureMode
* and sign since those are the methods phpseclib looks for to perform
* public key authentication.
*
* @package System_SSH_Agent
* @author Jim Wigginton
* @access internal
*/
class System_SSH_Agent_Identity
{
/**
* Key Object
*
* @var Crypt_RSA
* @access private
* @see self::getPublicKey()
*/
var $key;
/**
* Key Blob
*
* @var string
* @access private
* @see self::sign()
*/
var $key_blob;
/**
* Socket Resource
*
* @var resource
* @access private
* @see self::sign()
*/
var $fsock;
/**
* Signature flags
*
* @var int
* @access private
* @see self::sign()
* @see self::setHash()
*/
var $flags = 0;
/**
* Default Constructor.
*
* @param resource $fsock
* @return System_SSH_Agent_Identity
* @access private
*/
function __construct($fsock)
{
$this->fsock = $fsock;
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @param resource $fsock
* @access public
*/
function System_SSH_Agent_Identity($fsock)
{
$this->__construct($fsock);
}
/**
* Set Public Key
*
* Called by System_SSH_Agent::requestIdentities()
*
* @param Crypt_RSA $key
* @access private
*/
function setPublicKey($key)
{
$this->key = $key;
$this->key->setPublicKey();
}
/**
* Set Public Key
*
* Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key
* but this saves a small amount of computation.
*
* @param string $key_blob
* @access private
*/
function setPublicKeyBlob($key_blob)
{
$this->key_blob = $key_blob;
}
/**
* Get Public Key
*
* Wrapper for $this->key->getPublicKey()
*
* @param int $format optional
* @return mixed
* @access public
*/
function getPublicKey($format = null)
{
return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format);
}
/**
* Set Signature Mode
*
* Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie.
* ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1
*
* @param int $mode
* @access public
*/
function setSignatureMode($mode)
{
}
/**
* Set Hash
*
* ssh-agent doesn't support using hashes for RSA other than SHA1
*
* @param string $hash
* @access public
*/
function setHash($hash)
{
$this->flags = 0;
switch ($hash) {
case 'sha1':
break;
case 'sha256':
$this->flags = SYSTEM_SSH_AGENT_RSA2_256;
break;
case 'sha512':
$this->flags = SYSTEM_SSH_AGENT_RSA2_512;
break;
default:
user_error('The only supported hashes for RSA are sha1, sha256 and sha512');
}
}
/**
* Create a signature
*
* See "2.6.2 Protocol 2 private key signature request"
*
* @param string $message
* @return string
* @access public
*/
function sign($message)
{
// the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
$packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, $this->flags);
$packet = pack('Na*', strlen($packet), $packet);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed during signing');
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) {
user_error('Unable to retreive signature');
}
$signature_blob = fread($this->fsock, $length - 1);
$length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
if ($length != strlen($signature_blob)) {
user_error('Malformed signature blob');
}
$length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
if ($length > strlen($signature_blob) + 4) {
user_error('Malformed signature blob');
}
$type = $this->_string_shift($signature_blob, $length);
$this->_string_shift($signature_blob, 4);
return $signature_blob;
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
}
/**
* Pure-PHP ssh-agent client identity factory
*
* requestIdentities() method pumps out System_SSH_Agent_Identity objects
*
* @package System_SSH_Agent
* @author Jim Wigginton
* @access public
*/
class System_SSH_Agent
{
/**
* Socket Resource
*
* @var resource
* @access private
*/
var $fsock;
/**
* Agent forwarding status
*
* @access private
*/
var $forward_status = SYSTEM_SSH_AGENT_FORWARD_NONE;
/**
* Buffer for accumulating forwarded authentication
* agent data arriving on SSH data channel destined
* for agent unix socket
*
* @access private
*/
var $socket_buffer = '';
/**
* Tracking the number of bytes we are expecting
* to arrive for the agent socket on the SSH data
* channel
*/
var $expected_bytes = 0;
/**
* Default Constructor
*
* @return System_SSH_Agent
* @access public
*/
function __construct($address = null)
{
if (!$address) {
switch (true) {
case isset($_SERVER['SSH_AUTH_SOCK']):
$address = $_SERVER['SSH_AUTH_SOCK'];
break;
case isset($_ENV['SSH_AUTH_SOCK']):
$address = $_ENV['SSH_AUTH_SOCK'];
break;
default:
user_error('SSH_AUTH_SOCK not found');
return false;
}
}
$this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
if (!$this->fsock) {
user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
}
}
/**
* PHP4 compatible Default Constructor.
*
* @see self::__construct()
* @access public
*/
function System_SSH_Agent($address = null)
{
$this->__construct($address);
}
/**
* Request Identities
*
* See "2.5.2 Requesting a list of protocol 2 keys"
* Returns an array containing zero or more System_SSH_Agent_Identity objects
*
* @return array
* @access public
*/
function requestIdentities()
{
if (!$this->fsock) {
return array();
}
$packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed while requesting identities');
return array();
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) {
user_error('Unable to request identities');
return array();
}
$identities = array();
$keyCount = current(unpack('N', fread($this->fsock, 4)));
for ($i = 0; $i < $keyCount; $i++) {
$length = current(unpack('N', fread($this->fsock, 4)));
$key_blob = fread($this->fsock, $length);
$key_str = 'ssh-rsa ' . base64_encode($key_blob);
$length = current(unpack('N', fread($this->fsock, 4)));
if ($length) {
$key_str.= ' ' . fread($this->fsock, $length);
}
$length = current(unpack('N', substr($key_blob, 0, 4)));
$key_type = substr($key_blob, 4, $length);
switch ($key_type) {
case 'ssh-rsa':
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$key = new Crypt_RSA();
$key->loadKey($key_str);
break;
case 'ssh-dss':
// not currently supported
break;
}
// resources are passed by reference by default
if (isset($key)) {
$identity = new System_SSH_Agent_Identity($this->fsock);
$identity->setPublicKey($key);
$identity->setPublicKeyBlob($key_blob);
$identities[] = $identity;
unset($key);
}
}
return $identities;
}
/**
* Signal that agent forwarding should
* be requested when a channel is opened
*
* @param Net_SSH2 $ssh
* @return bool
* @access public
*/
function startSSHForwarding($ssh)
{
if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_NONE) {
$this->forward_status = SYSTEM_SSH_AGENT_FORWARD_REQUEST;
}
}
/**
* Request agent forwarding of remote server
*
* @param Net_SSH2 $ssh
* @return bool
* @access private
*/
function _request_forwarding($ssh)
{
$request_channel = $ssh->_get_open_channel();
if ($request_channel === false) {
return false;
}
$packet = pack(
'CNNa*C',
NET_SSH2_MSG_CHANNEL_REQUEST,
$ssh->server_channels[$request_channel],
strlen('auth-agent-req@openssh.com'),
'auth-agent-req@openssh.com',
1
);
$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;
if (!$ssh->_send_binary_packet($packet)) {
return false;
}
$response = $ssh->_get_channel_packet($request_channel);
if ($response === false) {
return false;
}
$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;
$this->forward_status = SYSTEM_SSH_AGENT_FORWARD_ACTIVE;
return true;
}
/**
* On successful channel open
*
* This method is called upon successful channel
* open to give the SSH Agent an opportunity
* to take further action. i.e. request agent forwarding
*
* @param Net_SSH2 $ssh
* @access private
*/
function _on_channel_open($ssh)
{
if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_REQUEST) {
$this->_request_forwarding($ssh);
}
}
/**
* Forward data to SSH Agent and return data reply
*
* @param string $data
* @return data from SSH Agent
* @access private
*/
function _forward_data($data)
{
if ($this->expected_bytes > 0) {
$this->socket_buffer.= $data;
$this->expected_bytes -= strlen($data);
} else {
$agent_data_bytes = current(unpack('N', $data));
$current_data_bytes = strlen($data);
$this->socket_buffer = $data;
if ($current_data_bytes != $agent_data_bytes + 4) {
$this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes;
return false;
}
}
if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
user_error('Connection closed attempting to forward data to SSH agent');
}
$this->socket_buffer = '';
$this->expected_bytes = 0;
$agent_reply_bytes = current(unpack('N', fread($this->fsock, 4)));
$agent_reply_data = fread($this->fsock, $agent_reply_bytes);
$agent_reply_data = current(unpack('a*', $agent_reply_data));
return pack('Na*', $agent_reply_bytes, $agent_reply_data);
}
}
================================================
FILE: assets/libraries/phpseclib/System/SSH_Agent.php
================================================
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
* @internal See http://api.libssh.org/rfc/PROTOCOL.agent
*/
require_once 'SSH/Agent.php';
================================================
FILE: assets/libraries/phpseclib/bootstrap.php
================================================
('0' + str).slice(-2)
const dateObj = new Date;
const date = `${dateObj.getFullYear()}-${padStart(dateObj.getMonth() + 1)}-${padStart(dateObj.getDate())}`;
const banner = `/**
* AnchorJS - v${pkg.version} - ${date}
* ${pkg.homepage}
* Copyright (c) ${dateObj.getFullYear()} Bryan Braun; Licensed ${pkg.license}
*/
`;
if (script.slice(0, 3) != '/**') {
fs.writeFileSync(filename, banner + script);
}
================================================
FILE: assets/vendor/chart.js/dist/Chart.extension.js
================================================
//
// Chart extension for making the bars rounded
// Code from: https://codepen.io/jedtrow/full/ygRYgo
//
Chart.elements.Rectangle.prototype.draw = function() {
var ctx = this._chart.ctx;
var vm = this._view;
var left, right, top, bottom, signX, signY, borderSkipped, radius;
var borderWidth = vm.borderWidth;
// Set Radius Here
// If radius is large enough to cause drawing errors a max radius is imposed
var cornerRadius = 6;
if (!vm.horizontal) {
// bar
left = vm.x - vm.width / 2;
right = vm.x + vm.width / 2;
top = vm.y;
bottom = vm.base;
signX = 1;
signY = bottom > top ? 1 : -1;
borderSkipped = vm.borderSkipped || 'bottom';
} else {
// horizontal bar
left = vm.base;
right = vm.x;
top = vm.y - vm.height / 2;
bottom = vm.y + vm.height / 2;
signX = right > left ? 1 : -1;
signY = 1;
borderSkipped = vm.borderSkipped || 'left';
}
// Canvas doesn't allow us to stroke inside the width so we can
// adjust the sizes to fit if we're setting a stroke on the line
if (borderWidth) {
// borderWidth shold be less than bar width and bar height.
var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
borderWidth = borderWidth > barSize ? barSize : borderWidth;
var halfStroke = borderWidth / 2;
// Adjust borderWidth when bar top position is near vm.base(zero).
var borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
var borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
var borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
var borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
// not become a vertical line?
if (borderLeft !== borderRight) {
top = borderTop;
bottom = borderBottom;
}
// not become a horizontal line?
if (borderTop !== borderBottom) {
left = borderLeft;
right = borderRight;
}
}
ctx.beginPath();
ctx.fillStyle = vm.backgroundColor;
ctx.strokeStyle = vm.borderColor;
ctx.lineWidth = borderWidth;
// Corner points, from bottom-left to bottom-right clockwise
// | 1 2 |
// | 0 3 |
var corners = [
[left, bottom],
[left, top],
[right, top],
[right, bottom]
];
// Find first (starting) corner with fallback to 'bottom'
var borders = ['bottom', 'left', 'top', 'right'];
var startCorner = borders.indexOf(borderSkipped, 0);
if (startCorner === -1) {
startCorner = 0;
}
function cornerAt(index) {
return corners[(startCorner + index) % 4];
}
// Draw rectangle from 'startCorner'
var corner = cornerAt(0);
ctx.moveTo(corner[0], corner[1]);
for (var i = 1; i < 4; i++) {
corner = cornerAt(i);
nextCornerId = i + 1;
if (nextCornerId == 4) {
nextCornerId = 0
}
nextCorner = cornerAt(nextCornerId);
width = corners[2][0] - corners[1][0];
height = corners[0][1] - corners[1][1];
x = corners[1][0];
y = corners[1][1];
var radius = cornerRadius;
// Fix radius being too large
if (radius > height / 2) {
radius = height / 2;
}
if (radius > width / 2) {
radius = width / 2;
}
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
}
ctx.fill();
if (borderWidth) {
ctx.stroke();
}
};
================================================
FILE: assets/vendor/holderjs/package.js
================================================
Package.describe({
summary: 'Holder uses SVG to render image placeholders entirely in browser.',
version: '2.9.4',
name: 'imsky:holder',
git: 'https://github.com/imsky/holder',
});
Package.onUse(function(api) {
api.versionsFrom('0.9.0');
api.export('Holder', 'client');
api.addFiles('holder.js', 'client');
});
================================================
FILE: assets/vendor/jquery/dist/core.js
================================================
/* global Symbol */
// Defining this global in .eslintrc.json would create a danger of using the global
// unguarded in another place, it seems safer to define global only for this module
define( [
"./var/arr",
"./var/document",
"./var/getProto",
"./var/slice",
"./var/concat",
"./var/push",
"./var/indexOf",
"./var/class2type",
"./var/toString",
"./var/hasOwn",
"./var/fnToString",
"./var/ObjectFunctionString",
"./var/support",
"./var/isFunction",
"./var/isWindow",
"./core/DOMEval",
"./core/toType"
], function( arr, document, getProto, slice, concat, push, indexOf,
class2type, toString, hasOwn, fnToString, ObjectFunctionString,
support, isFunction, isWindow, DOMEval, toType ) {
"use strict";
var
version = "3.3.1",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
},
// Support: Android <=4.0 only
// Make sure we trim BOM and NBSP
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
jQuery.fn = jQuery.prototype = {
// The current version of jQuery being used
jquery: version,
constructor: jQuery,
// The default length of a jQuery object is 0
length: 0,
toArray: function() {
return slice.call( this );
},
// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
get: function( num ) {
// Return all the elements in a clean array
if ( num == null ) {
return slice.call( this );
}
// Return just the one element from the set
return num < 0 ? this[ num + this.length ] : this[ num ];
},
// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function( elems ) {
// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
// Return the newly-formed element set
return ret;
},
// Execute a callback for every element in the matched set.
each: function( callback ) {
return jQuery.each( this, callback );
},
map: function( callback ) {
return this.pushStack( jQuery.map( this, function( elem, i ) {
return callback.call( elem, i, elem );
} ) );
},
slice: function() {
return this.pushStack( slice.apply( this, arguments ) );
},
first: function() {
return this.eq( 0 );
},
last: function() {
return this.eq( -1 );
},
eq: function( i ) {
var len = this.length,
j = +i + ( i < 0 ? len : 0 );
return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
},
end: function() {
return this.prevObject || this.constructor();
},
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
push: push,
sort: arr.sort,
splice: arr.splice
};
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[ 0 ] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !isFunction( target ) ) {
target = {};
}
// Extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( ( options = arguments[ i ] ) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
( copyIsArray = Array.isArray( copy ) ) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && Array.isArray( src ) ? src : [];
} else {
clone = src && jQuery.isPlainObject( src ) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
jQuery.extend( {
// Unique for each copy of jQuery on the page
expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
// Assume jQuery is ready without the ready module
isReady: true,
error: function( msg ) {
throw new Error( msg );
},
noop: function() {},
isPlainObject: function( obj ) {
var proto, Ctor;
// Detect obvious negatives
// Use toString instead of jQuery.type to catch host objects
if ( !obj || toString.call( obj ) !== "[object Object]" ) {
return false;
}
proto = getProto( obj );
// Objects with no prototype (e.g., `Object.create( null )`) are plain
if ( !proto ) {
return true;
}
// Objects with prototype are plain iff they were constructed by a global Object function
Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
},
isEmptyObject: function( obj ) {
/* eslint-disable no-unused-vars */
// See https://github.com/eslint/eslint/issues/6125
var name;
for ( name in obj ) {
return false;
}
return true;
},
// Evaluates a script in a global context
globalEval: function( code ) {
DOMEval( code );
},
each: function( obj, callback ) {
var length, i = 0;
if ( isArrayLike( obj ) ) {
length = obj.length;
for ( ; i < length; i++ ) {
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
break;
}
}
} else {
for ( i in obj ) {
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
break;
}
}
}
return obj;
},
// Support: Android <=4.0 only
trim: function( text ) {
return text == null ?
"" :
( text + "" ).replace( rtrim, "" );
},
// results is for internal usage only
makeArray: function( arr, results ) {
var ret = results || [];
if ( arr != null ) {
if ( isArrayLike( Object( arr ) ) ) {
jQuery.merge( ret,
typeof arr === "string" ?
[ arr ] : arr
);
} else {
push.call( ret, arr );
}
}
return ret;
},
inArray: function( elem, arr, i ) {
return arr == null ? -1 : indexOf.call( arr, elem, i );
},
// Support: Android <=4.0 only, PhantomJS 1 only
// push.apply(_, arraylike) throws on ancient WebKit
merge: function( first, second ) {
var len = +second.length,
j = 0,
i = first.length;
for ( ; j < len; j++ ) {
first[ i++ ] = second[ j ];
}
first.length = i;
return first;
},
grep: function( elems, callback, invert ) {
var callbackInverse,
matches = [],
i = 0,
length = elems.length,
callbackExpect = !invert;
// Go through the array, only saving the items
// that pass the validator function
for ( ; i < length; i++ ) {
callbackInverse = !callback( elems[ i ], i );
if ( callbackInverse !== callbackExpect ) {
matches.push( elems[ i ] );
}
}
return matches;
},
// arg is for internal usage only
map: function( elems, callback, arg ) {
var length, value,
i = 0,
ret = [];
// Go through the array, translating each of the items to their new values
if ( isArrayLike( elems ) ) {
length = elems.length;
for ( ; i < length; i++ ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret.push( value );
}
}
// Go through every key on the object,
} else {
for ( i in elems ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret.push( value );
}
}
}
// Flatten any nested arrays
return concat.apply( [], ret );
},
// A global GUID counter for objects
guid: 1,
// jQuery.support is not used in Core but other projects attach their
// properties to it so it needs to exist.
support: support
} );
if ( typeof Symbol === "function" ) {
jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
}
// Populate the class2type map
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
function( i, name ) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
} );
function isArrayLike( obj ) {
// Support: real iOS 8.2 only (not reproducible in simulator)
// `in` check used to prevent JIT error (gh-2145)
// hasOwn isn't used here due to false negatives
// regarding Nodelist length in IE
var length = !!obj && "length" in obj && obj.length,
type = toType( obj );
if ( isFunction( obj ) || isWindow( obj ) ) {
return false;
}
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}
return jQuery;
} );
================================================
FILE: assets/vendor/jquery.scrollbar/index.js
================================================
require('./jquery.scrollbar');
module.exports = 'jQueryScrollbar';
================================================
FILE: assets/vendor/jquery.scrollbar/jquery.scrollbar.css
================================================
/*************** SCROLLBAR BASE CSS ***************/
.scroll-wrapper {
overflow: hidden !important;
padding: 0 !important;
position: relative;
}
.scroll-wrapper > .scroll-content {
border: none !important;
box-sizing: content-box !important;
height: auto;
left: 0;
margin: 0;
max-height: none;
max-width: none !important;
overflow: scroll !important;
padding: 0;
position: relative !important;
top: 0;
width: auto !important;
}
.scroll-wrapper > .scroll-content::-webkit-scrollbar {
height: 0;
width: 0;
}
.scroll-wrapper.scroll--rtl {
direction: rtl;
}
.scroll-element {
box-sizing: content-box;
display: none;
}
.scroll-element div {
box-sizing: content-box;
}
.scroll-element .scroll-bar,
.scroll-element .scroll-arrow {
cursor: default;
}
.scroll-element.scroll-x.scroll-scrollx_visible, .scroll-element.scroll-y.scroll-scrolly_visible {
display: block;
}
.scroll-textarea {
border: 1px solid #cccccc;
border-top-color: #999999;
}
.scroll-textarea > .scroll-content {
overflow: hidden !important;
}
.scroll-textarea > .scroll-content > textarea {
border: none !important;
box-sizing: border-box;
height: 100% !important;
margin: 0;
max-height: none !important;
max-width: none !important;
overflow: scroll !important;
outline: none;
padding: 2px;
position: relative !important;
top: 0;
width: 100% !important;
}
.scroll-textarea > .scroll-content > textarea::-webkit-scrollbar {
height: 0;
width: 0;
}
/*************** SIMPLE INNER SCROLLBAR ***************/
.scrollbar-inner > .scroll-element,
.scrollbar-inner > .scroll-element div {
border: none;
margin: 0;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-inner > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-inner > .scroll-element.scroll-x {
bottom: 2px;
height: 8px;
left: 0;
width: 100%;
}
.scrollbar-inner > .scroll-element.scroll-y {
height: 100%;
right: 2px;
top: 0;
width: 8px;
}
.scrollbar-inner > .scroll-element .scroll-element_outer {
overflow: hidden;
}
.scrollbar-inner > .scroll-element .scroll-element_outer,
.scrollbar-inner > .scroll-element .scroll-element_track,
.scrollbar-inner > .scroll-element .scroll-bar {
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.scrollbar-inner > .scroll-element .scroll-element_track,
.scrollbar-inner > .scroll-element .scroll-bar {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";
filter: alpha(opacity=40);
opacity: 0.4;
}
.scrollbar-inner > .scroll-element .scroll-element_track {
background-color: #e0e0e0;
}
.scrollbar-inner > .scroll-element .scroll-bar {
background-color: #c2c2c2;
}
.scrollbar-inner > .scroll-element:hover .scroll-bar {
background-color: #919191;
}
.scrollbar-inner > .scroll-element.scroll-draggable .scroll-bar {
background-color: #919191;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-inner > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_track {
left: -12px;
}
.scrollbar-inner > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_track {
top: -12px;
}
.scrollbar-inner > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -12px;
}
.scrollbar-inner > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -12px;
}
/*************** SIMPLE OUTER SCROLLBAR ***************/
.scrollbar-outer > .scroll-element,
.scrollbar-outer > .scroll-element div {
border: none;
margin: 0;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-outer > .scroll-element {
background-color: #ffffff;
}
.scrollbar-outer > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-outer > .scroll-element.scroll-x {
bottom: 0;
height: 12px;
left: 0;
width: 100%;
}
.scrollbar-outer > .scroll-element.scroll-y {
height: 100%;
right: 0;
top: 0;
width: 12px;
}
.scrollbar-outer > .scroll-element.scroll-x .scroll-element_outer {
height: 8px;
top: 2px;
}
.scrollbar-outer > .scroll-element.scroll-y .scroll-element_outer {
left: 2px;
width: 8px;
}
.scrollbar-outer > .scroll-element .scroll-element_outer {
overflow: hidden;
}
.scrollbar-outer > .scroll-element .scroll-element_track {
background-color: #eeeeee;
}
.scrollbar-outer > .scroll-element .scroll-element_outer,
.scrollbar-outer > .scroll-element .scroll-element_track,
.scrollbar-outer > .scroll-element .scroll-bar {
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.scrollbar-outer > .scroll-element .scroll-bar {
background-color: #d9d9d9;
}
.scrollbar-outer > .scroll-element .scroll-bar:hover {
background-color: #c2c2c2;
}
.scrollbar-outer > .scroll-element.scroll-draggable .scroll-bar {
background-color: #919191;
}
/* scrollbar height/width & offset from container borders */
.scrollbar-outer > .scroll-content.scroll-scrolly_visible {
left: -12px;
margin-left: 12px;
}
.scrollbar-outer > .scroll-content.scroll-scrollx_visible {
top: -12px;
margin-top: 12px;
}
.scrollbar-outer > .scroll-element.scroll-x .scroll-bar {
min-width: 10px;
}
.scrollbar-outer > .scroll-element.scroll-y .scroll-bar {
min-height: 10px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-outer > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_track {
left: -14px;
}
.scrollbar-outer > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_track {
top: -14px;
}
.scrollbar-outer > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -14px;
}
.scrollbar-outer > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -14px;
}
/*************** SCROLLBAR MAC OS X ***************/
.scrollbar-macosx > .scroll-element,
.scrollbar-macosx > .scroll-element div {
background: none;
border: none;
margin: 0;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-macosx > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-macosx > .scroll-element .scroll-element_track {
display: none;
}
.scrollbar-macosx > .scroll-element .scroll-bar {
background-color: #6C6E71;
display: block;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=0);
opacity: 0;
-webkit-border-radius: 7px;
-moz-border-radius: 7px;
border-radius: 7px;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
-o-transition: opacity 0.2s linear;
-ms-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.scrollbar-macosx:hover > .scroll-element .scroll-bar,
.scrollbar-macosx > .scroll-element.scroll-draggable .scroll-bar {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";
filter: alpha(opacity=70);
opacity: 0.7;
}
.scrollbar-macosx > .scroll-element.scroll-x {
bottom: 0px;
height: 0px;
left: 0;
min-width: 100%;
overflow: visible;
width: 100%;
}
.scrollbar-macosx > .scroll-element.scroll-y {
height: 100%;
min-height: 100%;
right: 0px;
top: 0;
width: 0px;
}
/* scrollbar height/width & offset from container borders */
.scrollbar-macosx > .scroll-element.scroll-x .scroll-bar {
height: 7px;
min-width: 10px;
top: -9px;
}
.scrollbar-macosx > .scroll-element.scroll-y .scroll-bar {
left: -9px;
min-height: 10px;
width: 7px;
}
.scrollbar-macosx > .scroll-element.scroll-x .scroll-element_outer {
left: 2px;
}
.scrollbar-macosx > .scroll-element.scroll-x .scroll-element_size {
left: -4px;
}
.scrollbar-macosx > .scroll-element.scroll-y .scroll-element_outer {
top: 2px;
}
.scrollbar-macosx > .scroll-element.scroll-y .scroll-element_size {
top: -4px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-macosx > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -11px;
}
.scrollbar-macosx > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -11px;
}
/*************** SCROLLBAR LIGHT ***************/
.scrollbar-light > .scroll-element,
.scrollbar-light > .scroll-element div {
border: none;
margin: 0;
overflow: hidden;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-light > .scroll-element {
background-color: #ffffff;
}
.scrollbar-light > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-light > .scroll-element .scroll-element_outer {
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
.scrollbar-light > .scroll-element .scroll-element_size {
background: #dbdbdb;
background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2RiZGJkYiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNlOGU4ZTgiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+");
background: -moz-linear-gradient(left, #dbdbdb 0%, #e8e8e8 100%);
background: -webkit-gradient(linear, left top, right top, color-stop(0%, #dbdbdb), color-stop(100%, #e8e8e8));
background: -webkit-linear-gradient(left, #dbdbdb 0%, #e8e8e8 100%);
background: -o-linear-gradient(left, #dbdbdb 0%, #e8e8e8 100%);
background: -ms-linear-gradient(left, #dbdbdb 0%, #e8e8e8 100%);
background: linear-gradient(to right, #dbdbdb 0%, #e8e8e8 100%);
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
.scrollbar-light > .scroll-element.scroll-x {
bottom: 0;
height: 17px;
left: 0;
min-width: 100%;
width: 100%;
}
.scrollbar-light > .scroll-element.scroll-y {
height: 100%;
min-height: 100%;
right: 0;
top: 0;
width: 17px;
}
.scrollbar-light > .scroll-element .scroll-bar {
background: #fefefe;
background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZlZmVmZSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmNWY1ZjUiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+");
background: -moz-linear-gradient(left, #fefefe 0%, #f5f5f5 100%);
background: -webkit-gradient(linear, left top, right top, color-stop(0%, #fefefe), color-stop(100%, #f5f5f5));
background: -webkit-linear-gradient(left, #fefefe 0%, #f5f5f5 100%);
background: -o-linear-gradient(left, #fefefe 0%, #f5f5f5 100%);
background: -ms-linear-gradient(left, #fefefe 0%, #f5f5f5 100%);
background: linear-gradient(to right, #fefefe 0%, #f5f5f5 100%);
border: 1px solid #dbdbdb;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
/* scrollbar height/width & offset from container borders */
.scrollbar-light > .scroll-content.scroll-scrolly_visible {
left: -17px;
margin-left: 17px;
}
.scrollbar-light > .scroll-content.scroll-scrollx_visible {
top: -17px;
margin-top: 17px;
}
.scrollbar-light > .scroll-element.scroll-x .scroll-bar {
height: 10px;
min-width: 10px;
top: 0px;
}
.scrollbar-light > .scroll-element.scroll-y .scroll-bar {
left: 0px;
min-height: 10px;
width: 10px;
}
.scrollbar-light > .scroll-element.scroll-x .scroll-element_outer {
height: 12px;
left: 2px;
top: 2px;
}
.scrollbar-light > .scroll-element.scroll-x .scroll-element_size {
left: -4px;
}
.scrollbar-light > .scroll-element.scroll-y .scroll-element_outer {
left: 2px;
top: 2px;
width: 12px;
}
.scrollbar-light > .scroll-element.scroll-y .scroll-element_size {
top: -4px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-light > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -19px;
}
.scrollbar-light > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -19px;
}
.scrollbar-light > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_track {
left: -19px;
}
.scrollbar-light > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_track {
top: -19px;
}
/*************** SCROLLBAR RAIL ***************/
.scrollbar-rail > .scroll-element,
.scrollbar-rail > .scroll-element div {
border: none;
margin: 0;
overflow: hidden;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-rail > .scroll-element {
background-color: #ffffff;
}
.scrollbar-rail > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-rail > .scroll-element .scroll-element_size {
background-color: #999;
background-color: rgba(0, 0, 0, 0.3);
}
.scrollbar-rail > .scroll-element .scroll-element_outer:hover .scroll-element_size {
background-color: #666;
background-color: rgba(0, 0, 0, 0.5);
}
.scrollbar-rail > .scroll-element.scroll-x {
bottom: 0;
height: 12px;
left: 0;
min-width: 100%;
padding: 3px 0 2px;
width: 100%;
}
.scrollbar-rail > .scroll-element.scroll-y {
height: 100%;
min-height: 100%;
padding: 0 2px 0 3px;
right: 0;
top: 0;
width: 12px;
}
.scrollbar-rail > .scroll-element .scroll-bar {
background-color: #d0b9a0;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5);
}
.scrollbar-rail > .scroll-element .scroll-element_outer:hover .scroll-bar {
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6);
}
/* scrollbar height/width & offset from container borders */
.scrollbar-rail > .scroll-content.scroll-scrolly_visible {
left: -17px;
margin-left: 17px;
}
.scrollbar-rail > .scroll-content.scroll-scrollx_visible {
margin-top: 17px;
top: -17px;
}
.scrollbar-rail > .scroll-element.scroll-x .scroll-bar {
height: 10px;
min-width: 10px;
top: 1px;
}
.scrollbar-rail > .scroll-element.scroll-y .scroll-bar {
left: 1px;
min-height: 10px;
width: 10px;
}
.scrollbar-rail > .scroll-element.scroll-x .scroll-element_outer {
height: 15px;
left: 5px;
}
.scrollbar-rail > .scroll-element.scroll-x .scroll-element_size {
height: 2px;
left: -10px;
top: 5px;
}
.scrollbar-rail > .scroll-element.scroll-y .scroll-element_outer {
top: 5px;
width: 15px;
}
.scrollbar-rail > .scroll-element.scroll-y .scroll-element_size {
left: 5px;
top: -10px;
width: 2px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-rail > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -25px;
}
.scrollbar-rail > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -25px;
}
.scrollbar-rail > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_track {
left: -25px;
}
.scrollbar-rail > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_track {
top: -25px;
}
/*************** SCROLLBAR DYNAMIC ***************/
.scrollbar-dynamic > .scroll-element,
.scrollbar-dynamic > .scroll-element div {
background: none;
border: none;
margin: 0;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-dynamic > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-dynamic > .scroll-element.scroll-x {
bottom: 2px;
height: 7px;
left: 0;
min-width: 100%;
width: 100%;
}
.scrollbar-dynamic > .scroll-element.scroll-y {
height: 100%;
min-height: 100%;
right: 2px;
top: 0;
width: 7px;
}
.scrollbar-dynamic > .scroll-element .scroll-element_outer {
opacity: 0.3;
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
}
.scrollbar-dynamic > .scroll-element .scroll-element_size {
background-color: #cccccc;
opacity: 0;
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
-webkit-transition: opacity 0.2s;
-moz-transition: opacity 0.2s;
-o-transition: opacity 0.2s;
-ms-transition: opacity 0.2s;
transition: opacity 0.2s;
}
.scrollbar-dynamic > .scroll-element .scroll-bar {
background-color: #6c6e71;
-webkit-border-radius: 7px;
-moz-border-radius: 7px;
border-radius: 7px;
}
/* scrollbar height/width & offset from container borders */
.scrollbar-dynamic > .scroll-element.scroll-x .scroll-bar {
bottom: 0;
height: 7px;
min-width: 24px;
top: auto;
}
.scrollbar-dynamic > .scroll-element.scroll-y .scroll-bar {
left: auto;
min-height: 24px;
right: 0;
width: 7px;
}
.scrollbar-dynamic > .scroll-element.scroll-x .scroll-element_outer {
bottom: 0;
top: auto;
left: 2px;
-webkit-transition: height 0.2s;
-moz-transition: height 0.2s;
-o-transition: height 0.2s;
-ms-transition: height 0.2s;
transition: height 0.2s;
}
.scrollbar-dynamic > .scroll-element.scroll-y .scroll-element_outer {
left: auto;
right: 0;
top: 2px;
-webkit-transition: width 0.2s;
-moz-transition: width 0.2s;
-o-transition: width 0.2s;
-ms-transition: width 0.2s;
transition: width 0.2s;
}
.scrollbar-dynamic > .scroll-element.scroll-x .scroll-element_size {
left: -4px;
}
.scrollbar-dynamic > .scroll-element.scroll-y .scroll-element_size {
top: -4px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-dynamic > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -11px;
}
.scrollbar-dynamic > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -11px;
}
/* hover & drag */
.scrollbar-dynamic > .scroll-element:hover .scroll-element_outer,
.scrollbar-dynamic > .scroll-element.scroll-draggable .scroll-element_outer {
overflow: hidden;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";
filter: alpha(opacity=70);
opacity: 0.7;
}
.scrollbar-dynamic > .scroll-element:hover .scroll-element_outer .scroll-element_size,
.scrollbar-dynamic > .scroll-element.scroll-draggable .scroll-element_outer .scroll-element_size {
opacity: 1;
}
.scrollbar-dynamic > .scroll-element:hover .scroll-element_outer .scroll-bar,
.scrollbar-dynamic > .scroll-element.scroll-draggable .scroll-element_outer .scroll-bar {
height: 100%;
width: 100%;
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
}
.scrollbar-dynamic > .scroll-element.scroll-x:hover .scroll-element_outer,
.scrollbar-dynamic > .scroll-element.scroll-x.scroll-draggable .scroll-element_outer {
height: 20px;
min-height: 7px;
}
.scrollbar-dynamic > .scroll-element.scroll-y:hover .scroll-element_outer,
.scrollbar-dynamic > .scroll-element.scroll-y.scroll-draggable .scroll-element_outer {
min-width: 7px;
width: 20px;
}
/*************** SCROLLBAR GOOGLE CHROME ***************/
.scrollbar-chrome > .scroll-element,
.scrollbar-chrome > .scroll-element div {
border: none;
margin: 0;
overflow: hidden;
padding: 0;
position: absolute;
z-index: 10;
}
.scrollbar-chrome > .scroll-element {
background-color: #ffffff;
}
.scrollbar-chrome > .scroll-element div {
display: block;
height: 100%;
left: 0;
top: 0;
width: 100%;
}
.scrollbar-chrome > .scroll-element .scroll-element_track {
background: #f1f1f1;
border: 1px solid #dbdbdb;
}
.scrollbar-chrome > .scroll-element.scroll-x {
bottom: 0;
height: 16px;
left: 0;
min-width: 100%;
width: 100%;
}
.scrollbar-chrome > .scroll-element.scroll-y {
height: 100%;
min-height: 100%;
right: 0;
top: 0;
width: 16px;
}
.scrollbar-chrome > .scroll-element .scroll-bar {
background-color: #d9d9d9;
border: 1px solid #bdbdbd;
cursor: default;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
}
.scrollbar-chrome > .scroll-element .scroll-bar:hover {
background-color: #c2c2c2;
border-color: #a9a9a9;
}
.scrollbar-chrome > .scroll-element.scroll-draggable .scroll-bar {
background-color: #919191;
border-color: #7e7e7e;
}
/* scrollbar height/width & offset from container borders */
.scrollbar-chrome > .scroll-content.scroll-scrolly_visible {
left: -16px;
margin-left: 16px;
}
.scrollbar-chrome > .scroll-content.scroll-scrollx_visible {
top: -16px;
margin-top: 16px;
}
.scrollbar-chrome > .scroll-element.scroll-x .scroll-bar {
height: 8px;
min-width: 10px;
top: 3px;
}
.scrollbar-chrome > .scroll-element.scroll-y .scroll-bar {
left: 3px;
min-height: 10px;
width: 8px;
}
.scrollbar-chrome > .scroll-element.scroll-x .scroll-element_outer {
border-left: 1px solid #dbdbdb;
}
.scrollbar-chrome > .scroll-element.scroll-x .scroll-element_track {
height: 14px;
left: -3px;
}
.scrollbar-chrome > .scroll-element.scroll-x .scroll-element_size {
height: 14px;
left: -4px;
}
.scrollbar-chrome > .scroll-element.scroll-y .scroll-element_outer {
border-top: 1px solid #dbdbdb;
}
.scrollbar-chrome > .scroll-element.scroll-y .scroll-element_track {
top: -3px;
width: 14px;
}
.scrollbar-chrome > .scroll-element.scroll-y .scroll-element_size {
top: -4px;
width: 14px;
}
/* update scrollbar offset if both scrolls are visible */
.scrollbar-chrome > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_size {
left: -19px;
}
.scrollbar-chrome > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_size {
top: -19px;
}
.scrollbar-chrome > .scroll-element.scroll-x.scroll-scrolly_visible .scroll-element_track {
left: -19px;
}
.scrollbar-chrome > .scroll-element.scroll-y.scroll-scrollx_visible .scroll-element_track {
top: -19px;
}
================================================
FILE: assets/vendor/jquery.scrollbar/license-gpl.txt
================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
================================================
FILE: assets/vendor/jquery.scrollbar/license-mit.txt
================================================
Copyright (c) 2013 Yuriy Khabarov <13real008@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: assets/vendor/jquery.scrollbar/meteor/tests.js
================================================
'use strict';
Tinytest.add('Scrollbar integration', function (test) {
var div = document.createElement('div');
div.className = 'scrollbar-inner';
div.value = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam in.";
var scrollBar = jQuery('.scrollbar-inner').scrollbar();
console.log(scrollBar);
test.isNotNull(scrollBar, 'instantiation OK');
});
================================================
FILE: assets/vendor/jquery.scrollbar/package.js
================================================
// package metadata file for Meteor.js
'use strict';
var packageName = 'gromo:jquery.scrollbar'; // https://atmospherejs.com/mediatainment/switchery
var where = 'client'; // where to install: 'client' or 'server'. For both, pass nothing.
Package.describe({
name: packageName,
version: '0.2.11',
// Brief, one-line summary of the package.
summary: 'Cross-browser CSS customizable scrollbar with advanced features.',
// URL to the Git repository containing the source code for this package.
git: 'git@github.com:gromo/jquery.scrollbar.git'
});
Package.onUse(function (api) {
api.versionsFrom(['METEOR@0.9.0', 'METEOR@1.0']);
api.use('jquery', where);
api.addFiles(['jquery.scrollbar.js', 'jquery.scrollbar.css'], where);
});
Package.onTest(function (api) {
api.use([packageName, 'sanjo:jasmine'], where);
api.use(['webapp','tinytest'], where);
api.addFiles('meteor/tests.js', where); // testing specific files
});
================================================
FILE: assets/vendor/jquery.scrollbar/sass/config.rb
================================================
require 'compass/import-once/activate'
line_comments = false
================================================
FILE: assets/vendor/jquery.scrollbar/scrollbar.jquery.json
================================================
{
"name": "scrollbar",
"title": "jQuery Scrollbar",
"description": "Cross-browser CSS customizable scrollbar with advanced features: standard scroll behavior in all browsers/devices, responsive design support (no fixed height or width required), horizontal/vertical scrollbar or both, external scrollbars, automatically hide/show scrollbars (if content/container size is changed) and more...",
"keywords": [
"scroll",
"scrollbar"
],
"version": "0.2.11",
"author": {
"name": "Yuriy Khabarov",
"email": "13real008@gmail.com"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/gromo/jquery.scrollbar/blob/master/license-mit.txt"
},
{
"type": "GPLv2",
"url": "https://github.com/gromo/jquery.scrollbar/blob/master/license-gpl.txt"
}
],
"homepage": "http://gromo.github.io/jquery.scrollbar/",
"download": "http://gromo.github.io/jquery.scrollbar/jquery.scrollbar.zip",
"demo": "http://gromo.github.io/jquery.scrollbar/demo/basic.html",
"dependencies": {
"jquery": ">=1.7"
}
}
================================================
FILE: assets/vendor/nucleo/css/nucleo-svg.css
================================================
/* Generated using nucleoapp.com */
/* --------------------------------
Icon colors
-------------------------------- */
.icon {
display: inline-block;
/* icon primary color */
color: #111111;
height: 1em;
width: 1em;
}
.icon use {
/* icon secondary color - fill */
fill: #7ea6f6;
}
.icon.icon-outline use {
/* icon secondary color - stroke */
stroke: #7ea6f6;
}
/* --------------------------------
Change icon size
-------------------------------- */
.icon-xs {
height: 0.5em;
width: 0.5em;
}
.icon-sm {
height: 0.8em;
width: 0.8em;
}
.icon-lg {
height: 1.6em;
width: 1.6em;
}
.icon-xl {
height: 2em;
width: 2em;
}
/* --------------------------------
Align icon and text
-------------------------------- */
.icon-text-aligner {
/* add this class to parent element that contains icon + text */
display: flex;
align-items: center;
}
.icon-text-aligner .icon {
color: inherit;
margin-right: 0.4em;
}
.icon-text-aligner .icon use {
color: inherit;
fill: currentColor;
}
.icon-text-aligner .icon.icon-outline use {
stroke: currentColor;
}
/* --------------------------------
Icon reset values - used to enable color customizations
-------------------------------- */
.icon {
fill: currentColor;
stroke: none;
}
.icon.icon-outline {
fill: none;
stroke: currentColor;
}
.icon use {
stroke: none;
}
.icon.icon-outline use {
fill: none;
}
/* --------------------------------
Stroke effects - Nucleo outline icons
- 16px icons -> up to 1px stroke (16px outline icons do not support stroke changes)
- 24px, 32px icons -> up to 2px stroke
- 48px, 64px icons -> up to 4px stroke
-------------------------------- */
.icon-outline.icon-stroke-1 {
stroke-width: 1px;
}
.icon-outline.icon-stroke-2 {
stroke-width: 2px;
}
.icon-outline.icon-stroke-3 {
stroke-width: 3px;
}
.icon-outline.icon-stroke-4 {
stroke-width: 4px;
}
.icon-outline.icon-stroke-1 use,
.icon-outline.icon-stroke-3 use {
-webkit-transform: translateX(0.5px) translateY(0.5px);
-moz-transform: translateX(0.5px) translateY(0.5px);
-ms-transform: translateX(0.5px) translateY(0.5px);
-o-transform: translateX(0.5px) translateY(0.5px);
transform: translateX(0.5px) translateY(0.5px);
}
================================================
FILE: assets/vendor/nucleo/css/nucleo.css
================================================
/*--------------------------------
hermes-dashboard-icons Web Font - built using nucleoapp.com
License - nucleoapp.com/license/
-------------------------------- */
@font-face {
font-family: 'NucleoIcons';
src: url('../fonts/nucleo-icons.eot');
src: url('../fonts/nucleo-icons.eot') format('embedded-opentype'), url('../fonts/nucleo-icons.woff2') format('woff2'), url('../fonts/nucleo-icons.woff') format('woff'), url('../fonts/nucleo-icons.ttf') format('truetype'), url('../fonts/nucleo-icons.svg') format('svg');
font-weight: normal;
font-style: normal;
}
/*------------------------
base class definition
-------------------------*/
.ni {
display: inline-block;
font: normal normal normal 14px/1 NucleoIcons;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/*------------------------
change icon size
-------------------------*/
.ni-lg {
font-size: 1.33333333em;
line-height: 0.75em;
vertical-align: -15%;
}
.ni-2x {
font-size: 2em;
}
.ni-3x {
font-size: 3em;
}
.ni-4x {
font-size: 4em;
}
.ni-5x {
font-size: 5em;
}
/*----------------------------------
add a square/circle background
-----------------------------------*/
.ni.square,
.ni.circle {
padding: 0.33333333em;
vertical-align: -16%;
background-color: #eee;
}
.ni.circle {
border-radius: 50%;
}
/*------------------------
list icons
-------------------------*/
.ni-ul {
padding-left: 0;
margin-left: 2.14285714em;
list-style-type: none;
}
.ni-ul > li {
position: relative;
}
.ni-ul > li > .ni {
position: absolute;
left: -1.57142857em;
top: 0.14285714em;
text-align: center;
}
.ni-ul > li > .ni.lg {
top: 0;
left: -1.35714286em;
}
.ni-ul > li > .ni.circle,
.ni-ul > li > .ni.square {
top: -0.19047619em;
left: -1.9047619em;
}
/*------------------------
spinning icons
-------------------------*/
.ni.spin {
-webkit-animation: nc-spin 2s infinite linear;
-moz-animation: nc-spin 2s infinite linear;
animation: nc-spin 2s infinite linear;
}
@-webkit-keyframes nc-spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@-moz-keyframes nc-spin {
0% {
-moz-transform: rotate(0deg);
}
100% {
-moz-transform: rotate(360deg);
}
}
@keyframes nc-spin {
0% {
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-ms-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
/*------------------------
rotated/flipped icons
-------------------------*/
.ni.rotate-90 {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);
}
.ni.rotate-180 {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
}
.ni.rotate-270 {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
-webkit-transform: rotate(270deg);
-moz-transform: rotate(270deg);
-ms-transform: rotate(270deg);
-o-transform: rotate(270deg);
transform: rotate(270deg);
}
.ni.flip-y {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0);
-webkit-transform: scale(-1, 1);
-moz-transform: scale(-1, 1);
-ms-transform: scale(-1, 1);
-o-transform: scale(-1, 1);
transform: scale(-1, 1);
}
.ni.flip-x {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
-webkit-transform: scale(1, -1);
-moz-transform: scale(1, -1);
-ms-transform: scale(1, -1);
-o-transform: scale(1, -1);
transform: scale(1, -1);
}
/*------------------------
font icons
-------------------------*/
.ni-active-40::before {
content: "\ea02";
}
.ni-air-baloon::before {
content: "\ea03";
}
.ni-album-2::before {
content: "\ea04";
}
.ni-align-center::before {
content: "\ea05";
}
.ni-align-left-2::before {
content: "\ea06";
}
.ni-ambulance::before {
content: "\ea07";
}
.ni-app::before {
content: "\ea08";
}
.ni-archive-2::before {
content: "\ea09";
}
.ni-atom::before {
content: "\ea0a";
}
.ni-badge::before {
content: "\ea0b";
}
.ni-bag-17::before {
content: "\ea0c";
}
.ni-basket::before {
content: "\ea0d";
}
.ni-bell-55::before {
content: "\ea0e";
}
.ni-bold-down::before {
content: "\ea0f";
}
.ni-bold-left::before {
content: "\ea10";
}
.ni-bold-right::before {
content: "\ea11";
}
.ni-bold-up::before {
content: "\ea12";
}
.ni-bold::before {
content: "\ea13";
}
.ni-book-bookmark::before {
content: "\ea14";
}
.ni-books::before {
content: "\ea15";
}
.ni-box-2::before {
content: "\ea16";
}
.ni-briefcase-24::before {
content: "\ea17";
}
.ni-building::before {
content: "\ea18";
}
.ni-bulb-61::before {
content: "\ea19";
}
.ni-bullet-list-67::before {
content: "\ea1a";
}
.ni-bus-front-12::before {
content: "\ea1b";
}
.ni-button-pause::before {
content: "\ea1c";
}
.ni-button-play::before {
content: "\ea1d";
}
.ni-button-power::before {
content: "\ea1e";
}
.ni-calendar-grid-58::before {
content: "\ea1f";
}
.ni-camera-compact::before {
content: "\ea20";
}
.ni-caps-small::before {
content: "\ea21";
}
.ni-cart::before {
content: "\ea22";
}
.ni-chart-bar-32::before {
content: "\ea23";
}
.ni-chart-pie-35::before {
content: "\ea24";
}
.ni-chat-round::before {
content: "\ea25";
}
.ni-check-bold::before {
content: "\ea26";
}
.ni-circle-08::before {
content: "\ea27";
}
.ni-cloud-download-95::before {
content: "\ea28";
}
.ni-cloud-upload-96::before {
content: "\ea29";
}
.ni-compass-04::before {
content: "\ea2a";
}
.ni-controller::before {
content: "\ea2b";
}
.ni-credit-card::before {
content: "\ea2c";
}
.ni-curved-next::before {
content: "\ea2d";
}
.ni-delivery-fast::before {
content: "\ea2e";
}
.ni-diamond::before {
content: "\ea2f";
}
.ni-email-83::before {
content: "\ea30";
}
.ni-fat-add::before {
content: "\ea31";
}
.ni-fat-delete::before {
content: "\ea32";
}
.ni-fat-remove::before {
content: "\ea33";
}
.ni-favourite-28::before {
content: "\ea34";
}
.ni-folder-17::before {
content: "\ea35";
}
.ni-glasses-2::before {
content: "\ea36";
}
.ni-hat-3::before {
content: "\ea37";
}
.ni-headphones::before {
content: "\ea38";
}
.ni-html5::before {
content: "\ea39";
}
.ni-istanbul::before {
content: "\ea3a";
}
.ni-key-25::before {
content: "\ea3b";
}
.ni-laptop::before {
content: "\ea3c";
}
.ni-like-2::before {
content: "\ea3d";
}
.ni-lock-circle-open::before {
content: "\ea3e";
}
.ni-map-big::before {
content: "\ea3f";
}
.ni-mobile-button::before {
content: "\ea40";
}
.ni-money-coins::before {
content: "\ea41";
}
.ni-note-03::before {
content: "\ea42";
}
.ni-notification-70::before {
content: "\ea43";
}
.ni-palette::before {
content: "\ea44";
}
.ni-paper-diploma::before {
content: "\ea45";
}
.ni-pin-3::before {
content: "\ea46";
}
.ni-planet::before {
content: "\ea47";
}
.ni-ruler-pencil::before {
content: "\ea48";
}
.ni-satisfied::before {
content: "\ea49";
}
.ni-scissors::before {
content: "\ea4a";
}
.ni-send::before {
content: "\ea4b";
}
.ni-settings-gear-65::before {
content: "\ea4c";
}
.ni-settings::before {
content: "\ea4d";
}
.ni-single-02::before {
content: "\ea4e";
}
.ni-single-copy-04::before {
content: "\ea4f";
}
.ni-sound-wave::before {
content: "\ea50";
}
.ni-spaceship::before {
content: "\ea51";
}
.ni-square-pin::before {
content: "\ea52";
}
.ni-support-16::before {
content: "\ea53";
}
.ni-tablet-button::before {
content: "\ea54";
}
.ni-tag::before {
content: "\ea55";
}
.ni-tie-bow::before {
content: "\ea56";
}
.ni-time-alarm::before {
content: "\ea57";
}
.ni-trophy::before {
content: "\ea58";
}
.ni-tv-2::before {
content: "\ea59";
}
.ni-umbrella-13::before {
content: "\ea5a";
}
.ni-user-run::before {
content: "\ea5b";
}
.ni-vector::before {
content: "\ea5c";
}
.ni-watch-time::before {
content: "\ea5d";
}
.ni-world::before {
content: "\ea5e";
}
.ni-zoom-split-in::before {
content: "\ea5f";
}
.ni-collection::before {
content: "\ea60";
}
.ni-image::before {
content: "\ea61";
}
.ni-shop::before {
content: "\ea62";
}
.ni-ungroup::before {
content: "\ea63";
}
.ni-world-2::before {
content: "\ea64";
}
.ni-ui-04::before {
content: "\ea65";
}
/* all icon font classes list here */
================================================
FILE: assets/vendor/onscreen/dist/on-screen.es6.js
================================================
/**
* Attaches the scroll event handler
*
* @return {void}
*/
function attach() {
var container = this.options.container;
if (container instanceof HTMLElement) {
var style = window.getComputedStyle(container);
if (style.position === 'static') {
container.style.position = 'relative';
}
}
container.addEventListener('scroll', this._scroll);
window.addEventListener('resize', this._scroll);
this._scroll();
this.attached = true;
}
/**
* Checks an element's position in respect to the viewport
* and determines wether it's inside the viewport.
*
* @param {node} element The DOM node you want to check
* @return {boolean} A boolean value that indicates wether is on or off the viewport.
*/
function inViewport(el) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { tolerance: 0 };
if (!el) {
throw new Error('You should specify the element you want to test');
}
if (typeof el === 'string') {
el = document.querySelector(el);
}
var elRect = el.getBoundingClientRect();
return (
// Check bottom boundary
elRect.bottom - options.tolerance > 0 &&
// Check right boundary
elRect.right - options.tolerance > 0 &&
// Check left boundary
elRect.left + options.tolerance < (window.innerWidth || document.documentElement.clientWidth) &&
// Check top boundary
elRect.top + options.tolerance < (window.innerHeight || document.documentElement.clientHeight)
);
}
/**
* Checks an element's position in respect to a HTMLElement
* and determines wether it's within its boundaries.
*
* @param {node} element The DOM node you want to check
* @return {boolean} A boolean value that indicates wether is on or off the container.
*/
function inContainer(el) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { tolerance: 0, container: '' };
if (!el) {
throw new Error('You should specify the element you want to test');
}
if (typeof el === 'string') {
el = document.querySelector(el);
}
if (typeof options === 'string') {
options = {
tolerance: 0,
container: document.querySelector(options)
};
}
if (typeof options.container === 'string') {
options.container = document.querySelector(options.container);
}
if (options instanceof HTMLElement) {
options = {
tolerance: 0,
container: options
};
}
if (!options.container) {
throw new Error('You should specify a container element');
}
var containerRect = options.container.getBoundingClientRect();
return (
// // Check bottom boundary
el.offsetTop + el.clientHeight - options.tolerance > options.container.scrollTop &&
// Check right boundary
el.offsetLeft + el.clientWidth - options.tolerance > options.container.scrollLeft &&
// Check left boundary
el.offsetLeft + options.tolerance < containerRect.width + options.container.scrollLeft &&
// // Check top boundary
el.offsetTop + options.tolerance < containerRect.height + options.container.scrollTop
);
}
// TODO: Refactor this so it can be easily tested
/* istanbul ignore next */
function eventHandler() {
var trackedElements = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { tolerance: 0 };
var selectors = Object.keys(trackedElements);
var testVisibility = void 0;
if (!selectors.length) return;
if (options.container === window) {
testVisibility = inViewport;
} else {
testVisibility = inContainer;
}
selectors.forEach(function (selector) {
trackedElements[selector].nodes.forEach(function (item) {
if (testVisibility(item.node, options)) {
item.wasVisible = item.isVisible;
item.isVisible = true;
} else {
item.wasVisible = item.isVisible;
item.isVisible = false;
}
if (item.isVisible === true && item.wasVisible === false) {
if (!trackedElements[selector].enter) return;
Object.keys(trackedElements[selector].enter).forEach(function (callback) {
if (typeof trackedElements[selector].enter[callback] === 'function') {
trackedElements[selector].enter[callback](item.node, 'enter');
}
});
}
if (item.isVisible === false && item.wasVisible === true) {
if (!trackedElements[selector].leave) return;
Object.keys(trackedElements[selector].leave).forEach(function (callback) {
if (typeof trackedElements[selector].leave[callback] === 'function') {
trackedElements[selector].leave[callback](item.node, 'leave');
}
});
}
});
});
}
/**
* Debounces the scroll event to avoid performance issues
*
* @return {void}
*/
function debouncedScroll() {
var _this = this;
var timeout = void 0;
return function () {
clearTimeout(timeout);
timeout = setTimeout(function () {
eventHandler(_this.trackedElements, _this.options);
}, _this.options.debounce);
};
}
/**
* Removes the scroll event handler
*
* @return {void}
*/
function destroy() {
this.options.container.removeEventListener('scroll', this._scroll);
window.removeEventListener('resize', this._scroll);
this.attached = false;
}
/**
* Stops tracking elements matching a CSS selector. If a selector has no
* callbacks it gets removed.
*
* @param {string} event The event you want to stop tracking (enter or leave)
* @param {string} selector The CSS selector you want to stop tracking
* @return {void}
*/
function off(event, selector, handler) {
var enterCallbacks = Object.keys(this.trackedElements[selector].enter || {});
var leaveCallbacks = Object.keys(this.trackedElements[selector].leave || {});
if ({}.hasOwnProperty.call(this.trackedElements, selector)) {
if (handler) {
if (this.trackedElements[selector][event]) {
var callbackName = typeof handler === 'function' ? handler.name : handler;
delete this.trackedElements[selector][event][callbackName];
}
} else {
delete this.trackedElements[selector][event];
}
}
if (!enterCallbacks.length && !leaveCallbacks.length) {
delete this.trackedElements[selector];
}
}
/**
* Starts tracking elements matching a CSS selector
*
* @param {string} event The event you want to track (enter or leave)
* @param {string} selector The element you want to track
* @param {function} callback The callback function to handle the event
* @return {void}
*/
function on(event, selector, callback) {
var allowed = ['enter', 'leave'];
if (!event) throw new Error('No event given. Choose either enter or leave');
if (!selector) throw new Error('No selector to track');
if (allowed.indexOf(event) < 0) throw new Error(event + ' event is not supported');
if (!{}.hasOwnProperty.call(this.trackedElements, selector)) {
this.trackedElements[selector] = {};
}
this.trackedElements[selector].nodes = [];
for (var i = 0, elems = document.querySelectorAll(selector); i < elems.length; i++) {
var item = {
isVisible: false,
wasVisible: false,
node: elems[i]
};
this.trackedElements[selector].nodes.push(item);
}
if (typeof callback === 'function') {
if (!this.trackedElements[selector][event]) {
this.trackedElements[selector][event] = {};
}
this.trackedElements[selector][event][callback.name || 'anonymous'] = callback;
}
}
/**
* Observes DOM mutations and runs a callback function when
* detecting one.
*
* @param {node} obj The DOM node you want to observe
* @param {function} callback The callback function you want to call
* @return {void}
*/
function observeDOM(obj, callback) {
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
/* istanbul ignore else */
if (MutationObserver) {
var obs = new MutationObserver(callback);
obs.observe(obj, {
childList: true,
subtree: true
});
} else {
obj.addEventListener('DOMNodeInserted', callback, false);
obj.addEventListener('DOMNodeRemoved', callback, false);
}
}
/**
* Detects wether DOM nodes enter or leave the viewport
*
* @constructor
* @param {object} options The configuration object
*/
function OnScreen() {
var _this = this;
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { tolerance: 0, debounce: 100, container: window };
this.options = {};
this.trackedElements = {};
Object.defineProperties(this.options, {
container: {
configurable: false,
enumerable: false,
get: function get() {
var container = void 0;
if (typeof options.container === 'string') {
container = document.querySelector(options.container);
} else if (options.container instanceof HTMLElement) {
container = options.container;
}
return container || window;
},
set: function set(value) {
options.container = value;
}
},
debounce: {
get: function get() {
return parseInt(options.debounce, 10) || 100;
},
set: function set(value) {
options.debounce = value;
}
},
tolerance: {
get: function get() {
return parseInt(options.tolerance, 10) || 0;
},
set: function set(value) {
options.tolerance = value;
}
}
});
Object.defineProperty(this, '_scroll', {
enumerable: false,
configurable: false,
writable: false,
value: this._debouncedScroll.call(this)
});
observeDOM(document.querySelector('body'), function () {
Object.keys(_this.trackedElements).forEach(function (element) {
_this.on('enter', element);
_this.on('leave', element);
});
});
this.attach();
}
Object.defineProperties(OnScreen.prototype, {
_debouncedScroll: {
configurable: false,
writable: false,
enumerable: false,
value: debouncedScroll
},
attach: {
configurable: false,
writable: false,
enumerable: false,
value: attach
},
destroy: {
configurable: false,
writable: false,
enumerable: false,
value: destroy
},
off: {
configurable: false,
writable: false,
enumerable: false,
value: off
},
on: {
configurable: false,
writable: false,
enumerable: false,
value: on
}
});
OnScreen.check = inViewport;
export default OnScreen;
//# sourceMappingURL=on-screen.es6.js.map
================================================
FILE: assets/vendor/prismjs/components/index.js
================================================
var components = require('../components.js');
var peerDependentsMap = null;
function getPeerDependentsMap() {
var peerDependentsMap = {};
Object.keys(components.languages).forEach(function (language) {
if (language === 'meta') {
return false;
}
if (components.languages[language].peerDependencies) {
var peerDependencies = components.languages[language].peerDependencies;
if (!Array.isArray(peerDependencies)) {
peerDependencies = [peerDependencies];
}
peerDependencies.forEach(function (peerDependency) {
if (!peerDependentsMap[peerDependency]) {
peerDependentsMap[peerDependency] = [];
}
peerDependentsMap[peerDependency].push(language);
});
}
});
return peerDependentsMap;
}
function getPeerDependents(mainLanguage) {
if (!peerDependentsMap) {
peerDependentsMap = getPeerDependentsMap();
}
return peerDependentsMap[mainLanguage] || [];
}
function loadLanguages(arr, withoutDependencies) {
// If no argument is passed, load all components
if (!arr) {
arr = Object.keys(components.languages).filter(function (language) {
return language !== 'meta';
});
}
if (arr && !arr.length) {
return;
}
if (!Array.isArray(arr)) {
arr = [arr];
}
arr.forEach(function (language) {
if (!components.languages[language]) {
console.warn('Language does not exist ' + language);
return;
}
// Load dependencies first
if (!withoutDependencies && components.languages[language].require) {
loadLanguages(components.languages[language].require);
}
var pathToLanguage = './prism-' + language;
delete require.cache[require.resolve(pathToLanguage)];
delete Prism.languages[language];
require(pathToLanguage);
// Reload dependents
var dependents = getPeerDependents(language).filter(function (dependent) {
// If dependent language was already loaded,
// we want to reload it.
if (Prism.languages[dependent]) {
delete Prism.languages[dependent];
return true;
}
return false;
});
if (dependents.length) {
loadLanguages(dependents, true);
}
});
}
module.exports = function (arr) {
// Don't expose withoutDependencies
loadLanguages(arr);
};
================================================
FILE: assets/vendor/prismjs/components.js
================================================
var components = {"core":{"meta":{"path":"components/prism-core.js","option":"mandatory"},"core":"Core"},"themes":{"meta":{"path":"themes/{id}.css","link":"index.html?theme={id}","exclusive":true},"prism":{"title":"Default","option":"default"},"prism-dark":"Dark","prism-funky":"Funky","prism-okaidia":{"title":"Okaidia","owner":"ocodia"},"prism-twilight":{"title":"Twilight","owner":"remybach"},"prism-coy":{"title":"Coy","owner":"tshedor"},"prism-solarizedlight":{"title":"Solarized Light","owner":"hectormatos2011 "},"prism-tomorrow":{"title":"Tomorrow Night","owner":"Rosey"}},"languages":{"meta":{"path":"components/prism-{id}","noCSS":true,"examplesPath":"examples/prism-{id}","addCheckAll":true},"markup":{"title":"Markup","alias":["html","xml","svg","mathml"],"aliasTitles":{"html":"HTML","xml":"XML","svg":"SVG","mathml":"MathML"},"option":"default"},"css":{"title":"CSS","option":"default","peerDependencies":"markup"},"clike":{"title":"C-like","option":"default","overrideExampleHeader":true},"javascript":{"title":"JavaScript","require":"clike","peerDependencies":"markup","alias":"js","option":"default"},"abap":{"title":"ABAP","owner":"dellagustin"},"actionscript":{"title":"ActionScript","require":"javascript","peerDependencies":"markup","owner":"Golmote"},"ada":{"title":"Ada","owner":"Lucretia"},"apacheconf":{"title":"Apache Configuration","owner":"GuiTeK"},"apl":{"title":"APL","owner":"ngn"},"applescript":{"title":"AppleScript","owner":"Golmote"},"arduino":{"title":"Arduino","require":"cpp","owner":"eisbehr-"},"arff":{"title":"ARFF","owner":"Golmote"},"asciidoc":{"title":"AsciiDoc","owner":"Golmote"},"asm6502":{"title":"6502 Assembly","owner":"kzurawel"},"aspnet":{"title":"ASP.NET (C#)","require":["markup","csharp"],"owner":"nauzilus"},"autohotkey":{"title":"AutoHotkey","owner":"aviaryan"},"autoit":{"title":"AutoIt","owner":"Golmote"},"bash":{"title":"Bash","owner":"zeitgeist87"},"basic":{"title":"BASIC","owner":"Golmote"},"batch":{"title":"Batch","alias":"shell","owner":"Golmote"},"bison":{"title":"Bison","require":"c","owner":"Golmote"},"brainfuck":{"title":"Brainfuck","owner":"Golmote"},"bro":{"title":"Bro","owner":"wayward710"},"c":{"title":"C","require":"clike","owner":"zeitgeist87"},"csharp":{"title":"C#","require":"clike","alias":"dotnet","owner":"mvalipour"},"cpp":{"title":"C++","require":"c","owner":"zeitgeist87"},"coffeescript":{"title":"CoffeeScript","require":"javascript","owner":"R-osey"},"clojure":{"title":"Clojure","owner":"troglotit"},"crystal":{"title":"Crystal","require":"ruby","owner":"MakeNowJust"},"csp":{"title":"Content-Security-Policy","owner":"ScottHelme"},"css-extras":{"title":"CSS Extras","require":"css","owner":"milesj"},"d":{"title":"D","require":"clike","owner":"Golmote"},"dart":{"title":"Dart","require":"clike","owner":"Golmote"},"diff":{"title":"Diff","owner":"uranusjr"},"django":{"title":"Django/Jinja2","require":"markup","peerDependencies":["css","javascript"],"alias":"jinja2","owner":"romanvm"},"docker":{"title":"Docker","owner":"JustinBeckwith"},"eiffel":{"title":"Eiffel","owner":"Conaclos"},"elixir":{"title":"Elixir","owner":"Golmote"},"elm":{"title":"Elm","owner":"zwilias"},"erb":{"title":"ERB","require":["ruby","markup-templating"],"owner":"Golmote"},"erlang":{"title":"Erlang","owner":"Golmote"},"fsharp":{"title":"F#","require":"clike","owner":"simonreynolds7"},"flow":{"title":"Flow","require":"javascript","owner":"Golmote"},"fortran":{"title":"Fortran","owner":"Golmote"},"gedcom":{"title":"GEDCOM","owner":"Golmote"},"gherkin":{"title":"Gherkin","owner":"hason"},"git":{"title":"Git","owner":"lgiraudel"},"glsl":{"title":"GLSL","require":"clike","owner":"Golmote"},"go":{"title":"Go","require":"clike","owner":"arnehormann"},"graphql":{"title":"GraphQL","owner":"Golmote"},"groovy":{"title":"Groovy","require":"clike","owner":"robfletcher"},"haml":{"title":"Haml","require":"ruby","peerDependencies":["css","coffeescript","erb","javascript","less","markdown","ruby","scss","textile"],"owner":"Golmote"},"handlebars":{"title":"Handlebars","require":"markup-templating","owner":"Golmote"},"haskell":{"title":"Haskell","owner":"bholst"},"haxe":{"title":"Haxe","require":"clike","owner":"Golmote"},"http":{"title":"HTTP","peerDependencies":["javascript","markup"],"owner":"danielgtaylor"},"hpkp":{"title":"HTTP Public-Key-Pins","owner":"ScottHelme"},"hsts":{"title":"HTTP Strict-Transport-Security","owner":"ScottHelme"},"ichigojam":{"title":"IchigoJam","owner":"BlueCocoa"},"icon":{"title":"Icon","owner":"Golmote"},"inform7":{"title":"Inform 7","owner":"Golmote"},"ini":{"title":"Ini","owner":"aviaryan"},"io":{"title":"Io","owner":"AlesTsurko"},"j":{"title":"J","owner":"Golmote"},"java":{"title":"Java","require":"clike","owner":"sherblot"},"jolie":{"title":"Jolie","require":"clike","owner":"thesave"},"json":{"title":"JSON","owner":"CupOfTea696"},"julia":{"title":"Julia","owner":"cdagnino"},"keyman":{"title":"Keyman","owner":"mcdurdin"},"kotlin":{"title":"Kotlin","require":"clike","owner":"Golmote"},"latex":{"title":"LaTeX","owner":"japborst"},"less":{"title":"Less","require":"css","owner":"Golmote"},"liquid":{"title":"Liquid","owner":"cinhtau"},"lisp":{"title":"Lisp","owner":"JuanCaicedo","alias":["emacs","elisp","emacs-lisp"]},"livescript":{"title":"LiveScript","owner":"Golmote"},"lolcode":{"title":"LOLCODE","owner":"Golmote"},"lua":{"title":"Lua","owner":"Golmote"},"makefile":{"title":"Makefile","owner":"Golmote"},"markdown":{"title":"Markdown","require":"markup","owner":"Golmote"},"markup-templating":{"title":"Markup templating","require":"markup","owner":"Golmote"},"matlab":{"title":"MATLAB","owner":"Golmote"},"mel":{"title":"MEL","owner":"Golmote"},"mizar":{"title":"Mizar","owner":"Golmote"},"monkey":{"title":"Monkey","owner":"Golmote"},"n4js":{"title":"N4JS","require":"javascript","owner":"bsmith-n4"},"nasm":{"title":"NASM","owner":"rbmj"},"nginx":{"title":"nginx","owner":"westonganger","require":"clike"},"nim":{"title":"Nim","owner":"Golmote"},"nix":{"title":"Nix","owner":"Golmote"},"nsis":{"title":"NSIS","owner":"idleberg"},"objectivec":{"title":"Objective-C","require":"c","owner":"uranusjr"},"ocaml":{"title":"OCaml","owner":"Golmote"},"opencl":{"title":"OpenCL","require":"cpp","peerDependencies":["c","cpp"],"overrideExampleHeader":true,"owner":"Milania1"},"oz":{"title":"Oz","owner":"Golmote"},"parigp":{"title":"PARI/GP","owner":"Golmote"},"parser":{"title":"Parser","require":"markup","owner":"Golmote"},"pascal":{"title":"Pascal","alias":"objectpascal","aliasTitles":{"objectpascal":"Object Pascal"},"owner":"Golmote"},"perl":{"title":"Perl","owner":"Golmote"},"php":{"title":"PHP","require":["clike","markup-templating"],"owner":"milesj"},"php-extras":{"title":"PHP Extras","require":"php","owner":"milesj"},"plsql":{"title":"PL/SQL","require":"sql","owner":"Golmote"},"powershell":{"title":"PowerShell","owner":"nauzilus"},"processing":{"title":"Processing","require":"clike","owner":"Golmote"},"prolog":{"title":"Prolog","owner":"Golmote"},"properties":{"title":".properties","owner":"Golmote"},"protobuf":{"title":"Protocol Buffers","require":"clike","owner":"just-boris"},"pug":{"title":"Pug","require":"javascript","peerDependencies":["coffeescript","ejs","handlebars","hogan","less","livescript","markdown","mustache","plates","scss","stylus","swig"],"owner":"Golmote"},"puppet":{"title":"Puppet","owner":"Golmote"},"pure":{"title":"Pure","peerDependencies":["c","cpp","fortran","ats","dsp"],"owner":"Golmote"},"python":{"title":"Python","owner":"multipetros"},"q":{"title":"Q (kdb+ database)","owner":"Golmote"},"qore":{"title":"Qore","require":"clike","owner":"temnroegg"},"r":{"title":"R","owner":"Golmote"},"jsx":{"title":"React JSX","require":["markup","javascript"],"owner":"vkbansal"},"tsx":{"title":"React TSX","require":["jsx","typescript"]},"renpy":{"title":"Ren'py","owner":"HyuchiaDiego"},"reason":{"title":"Reason","require":"clike","owner":"Golmote"},"rest":{"title":"reST (reStructuredText)","owner":"Golmote"},"rip":{"title":"Rip","owner":"ravinggenius"},"roboconf":{"title":"Roboconf","owner":"Golmote"},"ruby":{"title":"Ruby","require":"clike","owner":"samflores"},"rust":{"title":"Rust","owner":"Golmote"},"sas":{"title":"SAS","owner":"Golmote"},"sass":{"title":"Sass (Sass)","require":"css","owner":"Golmote"},"scss":{"title":"Sass (Scss)","require":"css","owner":"MoOx"},"scala":{"title":"Scala","require":"java","owner":"jozic"},"scheme":{"title":"Scheme","owner":"bacchus123"},"smalltalk":{"title":"Smalltalk","owner":"Golmote"},"smarty":{"title":"Smarty","require":"markup-templating","owner":"Golmote"},"sql":{"title":"SQL","owner":"multipetros"},"soy":{"title":"Soy (Closure Template)","require":"markup-templating","owner":"Golmote"},"stylus":{"title":"Stylus","owner":"vkbansal"},"swift":{"title":"Swift","require":"clike","owner":"chrischares"},"tap":{"title":"TAP","owner":"isaacs","require":"yaml"},"tcl":{"title":"Tcl","owner":"PeterChaplin"},"textile":{"title":"Textile","require":"markup","peerDependencies":"css","owner":"Golmote"},"tt2":{"title":"Template Toolkit 2","require":["clike","markup-templating"],"owner":"gflohr"},"twig":{"title":"Twig","require":"markup","owner":"brandonkelly"},"typescript":{"title":"TypeScript","require":"javascript","alias":"ts","owner":"vkbansal"},"vbnet":{"title":"VB.Net","require":"basic","owner":"Bigsby"},"velocity":{"title":"Velocity","require":"markup","owner":"Golmote"},"verilog":{"title":"Verilog","owner":"a-rey"},"vhdl":{"title":"VHDL","owner":"a-rey"},"vim":{"title":"vim","owner":"westonganger"},"visual-basic":{"title":"Visual Basic","owner":"Golmote","alias":"vb"},"wasm":{"title":"WebAssembly","owner":"Golmote"},"wiki":{"title":"Wiki markup","require":"markup","owner":"Golmote"},"xeora":{"title":"Xeora","require":"markup","owner":"freakmaxi"},"xojo":{"title":"Xojo (REALbasic)","owner":"Golmote"},"xquery":{"title":"XQuery","require":"markup","owner":"Golmote"},"yaml":{"title":"YAML","owner":"hason"}},"plugins":{"meta":{"path":"plugins/{id}/prism-{id}","link":"plugins/{id}/"},"line-highlight":"Line Highlight","line-numbers":{"title":"Line Numbers","owner":"kuba-kubula"},"show-invisibles":"Show Invisibles","autolinker":"Autolinker","wpd":"WebPlatform Docs","custom-class":{"title":"Custom Class","owner":"dvkndn","noCSS":true},"file-highlight":{"title":"File Highlight","noCSS":true},"show-language":{"title":"Show Language","owner":"nauzilus","noCSS":true,"require":"toolbar"},"jsonp-highlight":{"title":"JSONP Highlight","noCSS":true,"owner":"nauzilus"},"highlight-keywords":{"title":"Highlight Keywords","owner":"vkbansal","noCSS":true},"remove-initial-line-feed":{"title":"Remove initial line feed","owner":"Golmote","noCSS":true},"previewers":{"title":"Previewers","owner":"Golmote"},"autoloader":{"title":"Autoloader","owner":"Golmote","noCSS":true},"keep-markup":{"title":"Keep Markup","owner":"Golmote","after":"normalize-whitespace","noCSS":true},"command-line":{"title":"Command Line","owner":"chriswells0"},"unescaped-markup":"Unescaped Markup","normalize-whitespace":{"title":"Normalize Whitespace","owner":"zeitgeist87","after":"unescaped-markup","noCSS":true},"data-uri-highlight":{"title":"Data-URI Highlight","owner":"Golmote","noCSS":true},"toolbar":{"title":"Toolbar","owner":"mAAdhaTTah"},"copy-to-clipboard":{"title":"Copy to Clipboard Button","owner":"mAAdhaTTah","require":"toolbar","noCSS":true}}};
if (typeof module !== 'undefined' && module.exports) { module.exports = components; }
================================================
FILE: assets/vendor/prismjs/components.json
================================================
{
"core": {
"meta": {
"path": "components/prism-core.js",
"option": "mandatory"
},
"core": "Core"
},
"themes": {
"meta": {
"path": "themes/{id}.css",
"link": "index.html?theme={id}",
"exclusive": true
},
"prism": {
"title": "Default",
"option": "default"
},
"prism-dark": "Dark",
"prism-funky": "Funky",
"prism-okaidia": {
"title": "Okaidia",
"owner": "ocodia"
},
"prism-twilight": {
"title": "Twilight",
"owner": "remybach"
},
"prism-coy": {
"title": "Coy",
"owner": "tshedor"
},
"prism-solarizedlight": {
"title": "Solarized Light",
"owner": "hectormatos2011 "
},
"prism-tomorrow": {
"title": "Tomorrow Night",
"owner": "Rosey"
}
},
"languages": {
"meta": {
"path": "components/prism-{id}",
"noCSS": true,
"examplesPath": "examples/prism-{id}",
"addCheckAll": true
},
"markup": {
"title": "Markup",
"alias": ["html", "xml", "svg", "mathml"],
"aliasTitles": {
"html": "HTML",
"xml": "XML",
"svg": "SVG",
"mathml": "MathML"
},
"option": "default"
},
"css": {
"title": "CSS",
"option": "default",
"peerDependencies": "markup"
},
"clike": {
"title": "C-like",
"option": "default",
"overrideExampleHeader": true
},
"javascript": {
"title": "JavaScript",
"require": "clike",
"peerDependencies": "markup",
"alias": "js",
"option": "default"
},
"abap": {
"title": "ABAP",
"owner": "dellagustin"
},
"actionscript": {
"title": "ActionScript",
"require": "javascript",
"peerDependencies": "markup",
"owner": "Golmote"
},
"ada": {
"title": "Ada",
"owner": "Lucretia"
},
"apacheconf": {
"title": "Apache Configuration",
"owner": "GuiTeK"
},
"apl": {
"title": "APL",
"owner": "ngn"
},
"applescript": {
"title": "AppleScript",
"owner": "Golmote"
},
"arduino": {
"title": "Arduino",
"require": "cpp",
"owner": "eisbehr-"
},
"arff": {
"title": "ARFF",
"owner": "Golmote"
},
"asciidoc": {
"title": "AsciiDoc",
"owner": "Golmote"
},
"asm6502": {
"title": "6502 Assembly",
"owner": "kzurawel"
},
"aspnet": {
"title": "ASP.NET (C#)",
"require": ["markup", "csharp"],
"owner": "nauzilus"
},
"autohotkey": {
"title": "AutoHotkey",
"owner": "aviaryan"
},
"autoit": {
"title": "AutoIt",
"owner": "Golmote"
},
"bash": {
"title": "Bash",
"owner": "zeitgeist87"
},
"basic": {
"title": "BASIC",
"owner": "Golmote"
},
"batch": {
"title": "Batch",
"alias": "shell",
"owner": "Golmote"
},
"bison": {
"title": "Bison",
"require": "c",
"owner": "Golmote"
},
"brainfuck": {
"title": "Brainfuck",
"owner": "Golmote"
},
"bro": {
"title": "Bro",
"owner": "wayward710"
},
"c": {
"title": "C",
"require": "clike",
"owner": "zeitgeist87"
},
"csharp": {
"title": "C#",
"require": "clike",
"alias": "dotnet",
"owner": "mvalipour"
},
"cpp": {
"title": "C++",
"require": "c",
"owner": "zeitgeist87"
},
"coffeescript": {
"title": "CoffeeScript",
"require": "javascript",
"owner": "R-osey"
},
"clojure": {
"title": "Clojure",
"owner": "troglotit"
},
"crystal": {
"title": "Crystal",
"require": "ruby",
"owner": "MakeNowJust"
},
"csp": {
"title": "Content-Security-Policy",
"owner": "ScottHelme"
},
"css-extras": {
"title": "CSS Extras",
"require": "css",
"owner": "milesj"
},
"d": {
"title": "D",
"require": "clike",
"owner": "Golmote"
},
"dart": {
"title": "Dart",
"require": "clike",
"owner": "Golmote"
},
"diff": {
"title": "Diff",
"owner": "uranusjr"
},
"django": {
"title": "Django/Jinja2",
"require": "markup",
"peerDependencies": [
"css",
"javascript"
],
"alias": "jinja2",
"owner": "romanvm"
},
"docker": {
"title": "Docker",
"owner": "JustinBeckwith"
},
"eiffel": {
"title": "Eiffel",
"owner": "Conaclos"
},
"elixir": {
"title": "Elixir",
"owner": "Golmote"
},
"elm": {
"title": "Elm",
"owner": "zwilias"
},
"erb": {
"title": "ERB",
"require": ["ruby", "markup-templating"],
"owner": "Golmote"
},
"erlang": {
"title": "Erlang",
"owner": "Golmote"
},
"fsharp": {
"title": "F#",
"require": "clike",
"owner": "simonreynolds7"
},
"flow": {
"title": "Flow",
"require": "javascript",
"owner": "Golmote"
},
"fortran": {
"title": "Fortran",
"owner": "Golmote"
},
"gedcom": {
"title": "GEDCOM",
"owner": "Golmote"
},
"gherkin": {
"title": "Gherkin",
"owner": "hason"
},
"git": {
"title": "Git",
"owner": "lgiraudel"
},
"glsl": {
"title": "GLSL",
"require": "clike",
"owner": "Golmote"
},
"go": {
"title": "Go",
"require": "clike",
"owner": "arnehormann"
},
"graphql": {
"title": "GraphQL",
"owner": "Golmote"
},
"groovy": {
"title": "Groovy",
"require": "clike",
"owner": "robfletcher"
},
"haml": {
"title": "Haml",
"require": "ruby",
"peerDependencies": [
"css",
"coffeescript",
"erb",
"javascript",
"less",
"markdown",
"ruby",
"scss",
"textile"
],
"owner": "Golmote"
},
"handlebars": {
"title": "Handlebars",
"require": "markup-templating",
"owner": "Golmote"
},
"haskell": {
"title": "Haskell",
"owner": "bholst"
},
"haxe": {
"title": "Haxe",
"require": "clike",
"owner": "Golmote"
},
"http": {
"title": "HTTP",
"peerDependencies": [
"javascript",
"markup"
],
"owner": "danielgtaylor"
},
"hpkp": {
"title": "HTTP Public-Key-Pins",
"owner": "ScottHelme"
},
"hsts": {
"title": "HTTP Strict-Transport-Security",
"owner": "ScottHelme"
},
"ichigojam": {
"title": "IchigoJam",
"owner": "BlueCocoa"
},
"icon": {
"title": "Icon",
"owner": "Golmote"
},
"inform7": {
"title": "Inform 7",
"owner": "Golmote"
},
"ini": {
"title": "Ini",
"owner": "aviaryan"
},
"io": {
"title": "Io",
"owner": "AlesTsurko"
},
"j": {
"title": "J",
"owner": "Golmote"
},
"java": {
"title": "Java",
"require": "clike",
"owner": "sherblot"
},
"jolie": {
"title": "Jolie",
"require": "clike",
"owner": "thesave"
},
"json": {
"title": "JSON",
"owner": "CupOfTea696"
},
"julia": {
"title": "Julia",
"owner": "cdagnino"
},
"keyman": {
"title": "Keyman",
"owner": "mcdurdin"
},
"kotlin": {
"title": "Kotlin",
"require": "clike",
"owner": "Golmote"
},
"latex": {
"title": "LaTeX",
"owner": "japborst"
},
"less": {
"title": "Less",
"require": "css",
"owner": "Golmote"
},
"liquid": {
"title": "Liquid",
"owner": "cinhtau"
},
"lisp": {
"title": "Lisp",
"owner": "JuanCaicedo",
"alias": ["emacs", "elisp", "emacs-lisp"]
},
"livescript": {
"title": "LiveScript",
"owner": "Golmote"
},
"lolcode": {
"title": "LOLCODE",
"owner": "Golmote"
},
"lua": {
"title": "Lua",
"owner": "Golmote"
},
"makefile": {
"title": "Makefile",
"owner": "Golmote"
},
"markdown": {
"title": "Markdown",
"require": "markup",
"owner": "Golmote"
},
"markup-templating": {
"title": "Markup templating",
"require": "markup",
"owner": "Golmote"
},
"matlab": {
"title": "MATLAB",
"owner": "Golmote"
},
"mel": {
"title": "MEL",
"owner": "Golmote"
},
"mizar": {
"title": "Mizar",
"owner": "Golmote"
},
"monkey": {
"title": "Monkey",
"owner": "Golmote"
},
"n4js": {
"title": "N4JS",
"require": "javascript",
"owner": "bsmith-n4"
},
"nasm": {
"title": "NASM",
"owner": "rbmj"
},
"nginx": {
"title": "nginx",
"owner": "westonganger",
"require": "clike"
},
"nim": {
"title": "Nim",
"owner": "Golmote"
},
"nix": {
"title": "Nix",
"owner": "Golmote"
},
"nsis": {
"title": "NSIS",
"owner": "idleberg"
},
"objectivec": {
"title": "Objective-C",
"require": "c",
"owner": "uranusjr"
},
"ocaml": {
"title": "OCaml",
"owner": "Golmote"
},
"opencl": {
"title": "OpenCL",
"require": "cpp",
"peerDependencies": [
"c",
"cpp"
],
"overrideExampleHeader": true,
"owner": "Milania1"
},
"oz": {
"title": "Oz",
"owner": "Golmote"
},
"parigp": {
"title": "PARI/GP",
"owner": "Golmote"
},
"parser": {
"title": "Parser",
"require": "markup",
"owner": "Golmote"
},
"pascal": {
"title": "Pascal",
"alias": "objectpascal",
"aliasTitles": {
"objectpascal": "Object Pascal"
},
"owner": "Golmote"
},
"perl": {
"title": "Perl",
"owner": "Golmote"
},
"php": {
"title": "PHP",
"require": ["clike", "markup-templating"],
"owner": "milesj"
},
"php-extras": {
"title": "PHP Extras",
"require": "php",
"owner": "milesj"
},
"plsql": {
"title": "PL/SQL",
"require": "sql",
"owner": "Golmote"
},
"powershell": {
"title": "PowerShell",
"owner": "nauzilus"
},
"processing": {
"title": "Processing",
"require": "clike",
"owner": "Golmote"
},
"prolog": {
"title": "Prolog",
"owner": "Golmote"
},
"properties": {
"title": ".properties",
"owner": "Golmote"
},
"protobuf": {
"title": "Protocol Buffers",
"require": "clike",
"owner": "just-boris"
},
"pug": {
"title": "Pug",
"require": "javascript",
"peerDependencies": [
"coffeescript",
"ejs",
"handlebars",
"hogan",
"less",
"livescript",
"markdown",
"mustache",
"plates",
"scss",
"stylus",
"swig"
],
"owner": "Golmote"
},
"puppet": {
"title": "Puppet",
"owner": "Golmote"
},
"pure": {
"title": "Pure",
"peerDependencies": [
"c",
"cpp",
"fortran",
"ats",
"dsp"
],
"owner": "Golmote"
},
"python": {
"title": "Python",
"owner": "multipetros"
},
"q": {
"title": "Q (kdb+ database)",
"owner": "Golmote"
},
"qore": {
"title": "Qore",
"require": "clike",
"owner": "temnroegg"
},
"r": {
"title": "R",
"owner": "Golmote"
},
"jsx": {
"title": "React JSX",
"require": ["markup", "javascript"],
"owner": "vkbansal"
},
"tsx": {
"title": "React TSX",
"require": ["jsx", "typescript"]
},
"renpy": {
"title": "Ren'py",
"owner": "HyuchiaDiego"
},
"reason": {
"title": "Reason",
"require": "clike",
"owner": "Golmote"
},
"rest": {
"title": "reST (reStructuredText)",
"owner": "Golmote"
},
"rip": {
"title": "Rip",
"owner": "ravinggenius"
},
"roboconf": {
"title": "Roboconf",
"owner": "Golmote"
},
"ruby": {
"title": "Ruby",
"require": "clike",
"owner": "samflores"
},
"rust": {
"title": "Rust",
"owner": "Golmote"
},
"sas": {
"title": "SAS",
"owner": "Golmote"
},
"sass": {
"title": "Sass (Sass)",
"require": "css",
"owner": "Golmote"
},
"scss": {
"title": "Sass (Scss)",
"require": "css",
"owner": "MoOx"
},
"scala": {
"title": "Scala",
"require": "java",
"owner": "jozic"
},
"scheme": {
"title": "Scheme",
"owner": "bacchus123"
},
"smalltalk": {
"title": "Smalltalk",
"owner": "Golmote"
},
"smarty": {
"title": "Smarty",
"require": "markup-templating",
"owner": "Golmote"
},
"sql": {
"title": "SQL",
"owner": "multipetros"
},
"soy": {
"title": "Soy (Closure Template)",
"require": "markup-templating",
"owner": "Golmote"
},
"stylus": {
"title": "Stylus",
"owner": "vkbansal"
},
"swift": {
"title": "Swift",
"require": "clike",
"owner": "chrischares"
},
"tap": {
"title": "TAP",
"owner": "isaacs",
"require": "yaml"
},
"tcl": {
"title": "Tcl",
"owner": "PeterChaplin"
},
"textile": {
"title": "Textile",
"require": "markup",
"peerDependencies": "css",
"owner": "Golmote"
},
"tt2": {
"title": "Template Toolkit 2",
"require": ["clike", "markup-templating"],
"owner": "gflohr"
},
"twig": {
"title": "Twig",
"require": "markup",
"owner": "brandonkelly"
},
"typescript": {
"title": "TypeScript",
"require": "javascript",
"alias": "ts",
"owner": "vkbansal"
},
"vbnet": {
"title": "VB.Net",
"require": "basic",
"owner": "Bigsby"
},
"velocity": {
"title": "Velocity",
"require": "markup",
"owner": "Golmote"
},
"verilog": {
"title": "Verilog",
"owner": "a-rey"
},
"vhdl": {
"title": "VHDL",
"owner": "a-rey"
},
"vim": {
"title": "vim",
"owner": "westonganger"
},
"visual-basic": {
"title": "Visual Basic",
"owner": "Golmote",
"alias": "vb"
},
"wasm": {
"title": "WebAssembly",
"owner": "Golmote"
},
"wiki": {
"title": "Wiki markup",
"require": "markup",
"owner": "Golmote"
},
"xeora": {
"title": "Xeora",
"require": "markup",
"owner": "freakmaxi"
},
"xojo": {
"title": "Xojo (REALbasic)",
"owner": "Golmote"
},
"xquery": {
"title": "XQuery",
"require": "markup",
"owner": "Golmote"
},
"yaml": {
"title": "YAML",
"owner": "hason"
}
},
"plugins": {
"meta": {
"path": "plugins/{id}/prism-{id}",
"link": "plugins/{id}/"
},
"line-highlight": "Line Highlight",
"line-numbers": {
"title": "Line Numbers",
"owner": "kuba-kubula"
},
"show-invisibles": "Show Invisibles",
"autolinker": "Autolinker",
"wpd": "WebPlatform Docs",
"custom-class": {
"title": "Custom Class",
"owner": "dvkndn",
"noCSS": true
},
"file-highlight": {
"title": "File Highlight",
"noCSS": true
},
"show-language": {
"title": "Show Language",
"owner": "nauzilus",
"noCSS": true,
"require": "toolbar"
},
"jsonp-highlight": {
"title": "JSONP Highlight",
"noCSS": true,
"owner": "nauzilus"
},
"highlight-keywords": {
"title": "Highlight Keywords",
"owner": "vkbansal",
"noCSS": true
},
"remove-initial-line-feed": {
"title": "Remove initial line feed",
"owner": "Golmote",
"noCSS": true
},
"previewers": {
"title": "Previewers",
"owner": "Golmote"
},
"autoloader": {
"title": "Autoloader",
"owner": "Golmote",
"noCSS": true
},
"keep-markup": {
"title": "Keep Markup",
"owner": "Golmote",
"after": "normalize-whitespace",
"noCSS": true
},
"command-line": {
"title": "Command Line",
"owner": "chriswells0"
},
"unescaped-markup": "Unescaped Markup",
"normalize-whitespace": {
"title": "Normalize Whitespace",
"owner": "zeitgeist87",
"after": "unescaped-markup",
"noCSS": true
},
"data-uri-highlight": {
"title": "Data-URI Highlight",
"owner": "Golmote",
"noCSS": true
},
"toolbar": {
"title": "Toolbar",
"owner": "mAAdhaTTah"
},
"copy-to-clipboard": {
"title": "Copy to Clipboard Button",
"owner": "mAAdhaTTah",
"require": "toolbar",
"noCSS": true
}
}
}
================================================
FILE: assets/vendor/prismjs/plugins/autolinker/prism-autolinker.css
================================================
.token a {
color: inherit;
}
================================================
FILE: assets/vendor/prismjs/plugins/command-line/prism-command-line.css
================================================
.command-line-prompt {
border-right: 1px solid #999;
display: block;
float: left;
font-size: 100%;
letter-spacing: -1px;
margin-right: 1em;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.command-line-prompt > span:before {
color: #999;
content: ' ';
display: block;
padding-right: 0.8em;
}
.command-line-prompt > span[data-user]:before {
content: "[" attr(data-user) "@" attr(data-host) "] $";
}
.command-line-prompt > span[data-user="root"]:before {
content: "[" attr(data-user) "@" attr(data-host) "] #";
}
.command-line-prompt > span[data-prompt]:before {
content: attr(data-prompt);
}
================================================
FILE: assets/vendor/prismjs/plugins/line-highlight/prism-line-highlight.css
================================================
pre[data-line] {
position: relative;
padding: 1em 0 1em 3em;
}
.line-highlight {
position: absolute;
left: 0;
right: 0;
padding: inherit 0;
margin-top: 1em; /* Same as .prism’s padding-top */
background: hsla(24, 20%, 50%,.08);
background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
pointer-events: none;
line-height: inherit;
white-space: pre;
}
.line-highlight:before,
.line-highlight[data-end]:after {
content: attr(data-start);
position: absolute;
top: .4em;
left: .6em;
min-width: 1em;
padding: 0 .5em;
background-color: hsla(24, 20%, 50%,.4);
color: hsl(24, 20%, 95%);
font: bold 65%/1.5 sans-serif;
text-align: center;
vertical-align: .3em;
border-radius: 999px;
text-shadow: none;
box-shadow: 0 1px white;
}
.line-highlight[data-end]:after {
content: attr(data-end);
top: auto;
bottom: .4em;
}
.line-numbers .line-highlight:before,
.line-numbers .line-highlight:after {
content: none;
}
================================================
FILE: assets/vendor/prismjs/plugins/line-numbers/prism-line-numbers.css
================================================
pre[class*="language-"].line-numbers {
position: relative;
padding-left: 3.8em;
counter-reset: linenumber;
}
pre[class*="language-"].line-numbers > code {
position: relative;
white-space: inherit;
}
.line-numbers .line-numbers-rows {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: -3.8em;
width: 3em; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line-numbers-rows > span {
pointer-events: none;
display: block;
counter-increment: linenumber;
}
.line-numbers-rows > span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}
================================================
FILE: assets/vendor/prismjs/plugins/previewers/prism-previewers.css
================================================
.prism-previewer,
.prism-previewer:before,
.prism-previewer:after {
position: absolute;
pointer-events: none;
}
.prism-previewer,
.prism-previewer:after {
left: 50%;
}
.prism-previewer {
margin-top: -48px;
width: 32px;
height: 32px;
margin-left: -16px;
opacity: 0;
-webkit-transition: opacity .25s;
-o-transition: opacity .25s;
transition: opacity .25s;
}
.prism-previewer.flipped {
margin-top: 0;
margin-bottom: -48px;
}
.prism-previewer:before,
.prism-previewer:after {
content: '';
position: absolute;
pointer-events: none;
}
.prism-previewer:before {
top: -5px;
right: -5px;
left: -5px;
bottom: -5px;
border-radius: 10px;
border: 5px solid #fff;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5) inset, 0 0 10px rgba(0, 0, 0, 0.75);
}
.prism-previewer:after {
top: 100%;
width: 0;
height: 0;
margin: 5px 0 0 -7px;
border: 7px solid transparent;
border-color: rgba(255, 0, 0, 0);
border-top-color: #fff;
}
.prism-previewer.flipped:after {
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: 5px;
border-top-color: rgba(255, 0, 0, 0);
border-bottom-color: #fff;
}
.prism-previewer.active {
opacity: 1;
}
.prism-previewer-angle:before {
border-radius: 50%;
background: #fff;
}
.prism-previewer-angle:after {
margin-top: 4px;
}
.prism-previewer-angle svg {
width: 32px;
height: 32px;
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
transform: rotate(-90deg);
}
.prism-previewer-angle[data-negative] svg {
-webkit-transform: scaleX(-1) rotate(-90deg);
-moz-transform: scaleX(-1) rotate(-90deg);
-ms-transform: scaleX(-1) rotate(-90deg);
-o-transform: scaleX(-1) rotate(-90deg);
transform: scaleX(-1) rotate(-90deg);
}
.prism-previewer-angle circle {
fill: transparent;
stroke: hsl(200, 10%, 20%);
stroke-opacity: 0.9;
stroke-width: 32;
stroke-dasharray: 0, 500;
}
.prism-previewer-gradient {
background-image: linear-gradient(45deg, #bbb 25%, transparent 25%, transparent 75%, #bbb 75%, #bbb), linear-gradient(45deg, #bbb 25%, #eee 25%, #eee 75%, #bbb 75%, #bbb);
background-size: 10px 10px;
background-position: 0 0, 5px 5px;
width: 64px;
margin-left: -32px;
}
.prism-previewer-gradient:before {
content: none;
}
.prism-previewer-gradient div {
position: absolute;
top: -5px;
left: -5px;
right: -5px;
bottom: -5px;
border-radius: 10px;
border: 5px solid #fff;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5) inset, 0 0 10px rgba(0, 0, 0, 0.75);
}
.prism-previewer-color {
background-image: linear-gradient(45deg, #bbb 25%, transparent 25%, transparent 75%, #bbb 75%, #bbb), linear-gradient(45deg, #bbb 25%, #eee 25%, #eee 75%, #bbb 75%, #bbb);
background-size: 10px 10px;
background-position: 0 0, 5px 5px;
}
.prism-previewer-color:before {
background-color: inherit;
background-clip: padding-box;
}
.prism-previewer-easing {
margin-top: -76px;
margin-left: -30px;
width: 60px;
height: 60px;
background: #333;
}
.prism-previewer-easing.flipped {
margin-bottom: -116px;
}
.prism-previewer-easing svg {
width: 60px;
height: 60px;
}
.prism-previewer-easing circle {
fill: hsl(200, 10%, 20%);
stroke: white;
}
.prism-previewer-easing path {
fill: none;
stroke: white;
stroke-linecap: round;
stroke-width: 4;
}
.prism-previewer-easing line {
stroke: white;
stroke-opacity: 0.5;
stroke-width: 2;
}
@-webkit-keyframes prism-previewer-time {
0% {
stroke-dasharray: 0, 500;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 100, 500;
stroke-dashoffset: 0;
}
100% {
stroke-dasharray: 0, 500;
stroke-dashoffset: -100;
}
}
@-o-keyframes prism-previewer-time {
0% {
stroke-dasharray: 0, 500;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 100, 500;
stroke-dashoffset: 0;
}
100% {
stroke-dasharray: 0, 500;
stroke-dashoffset: -100;
}
}
@-moz-keyframes prism-previewer-time {
0% {
stroke-dasharray: 0, 500;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 100, 500;
stroke-dashoffset: 0;
}
100% {
stroke-dasharray: 0, 500;
stroke-dashoffset: -100;
}
}
@keyframes prism-previewer-time {
0% {
stroke-dasharray: 0, 500;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 100, 500;
stroke-dashoffset: 0;
}
100% {
stroke-dasharray: 0, 500;
stroke-dashoffset: -100;
}
}
.prism-previewer-time:before {
border-radius: 50%;
background: #fff;
}
.prism-previewer-time:after {
margin-top: 4px;
}
.prism-previewer-time svg {
width: 32px;
height: 32px;
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
transform: rotate(-90deg);
}
.prism-previewer-time circle {
fill: transparent;
stroke: hsl(200, 10%, 20%);
stroke-opacity: 0.9;
stroke-width: 32;
stroke-dasharray: 0, 500;
stroke-dashoffset: 0;
-webkit-animation: prism-previewer-time linear infinite 3s;
-moz-animation: prism-previewer-time linear infinite 3s;
-o-animation: prism-previewer-time linear infinite 3s;
animation: prism-previewer-time linear infinite 3s;
}
================================================
FILE: assets/vendor/prismjs/plugins/show-invisibles/prism-show-invisibles.css
================================================
.token.tab:not(:empty),
.token.cr,
.token.lf,
.token.space {
position: relative;
}
.token.tab:not(:empty):before,
.token.cr:before,
.token.lf:before,
.token.space:before {
color: hsl(24, 20%, 85%);
position: absolute;
}
.token.tab:not(:empty):before {
content: '\21E5';
}
.token.cr:before {
content: '\240D';
}
.token.crlf:before {
content: '\240D\240A';
}
.token.lf:before {
content: '\240A';
}
.token.space:before {
content: '\00B7';
}
================================================
FILE: assets/vendor/prismjs/plugins/toolbar/prism-toolbar.css
================================================
div.code-toolbar {
position: relative;
}
div.code-toolbar > .toolbar {
position: absolute;
top: .3em;
right: .2em;
transition: opacity 0.3s ease-in-out;
opacity: 0;
}
div.code-toolbar:hover > .toolbar {
opacity: 1;
}
div.code-toolbar > .toolbar .toolbar-item {
display: inline-block;
}
div.code-toolbar > .toolbar a {
cursor: pointer;
}
div.code-toolbar > .toolbar button {
background: none;
border: 0;
color: inherit;
font: inherit;
line-height: normal;
overflow: visible;
padding: 0;
-webkit-user-select: none; /* for button */
-moz-user-select: none;
-ms-user-select: none;
}
div.code-toolbar > .toolbar a,
div.code-toolbar > .toolbar button,
div.code-toolbar > .toolbar span {
color: #bbb;
font-size: .8em;
padding: 0 .5em;
background: #f5f2f0;
background: rgba(224, 224, 224, 0.2);
box-shadow: 0 2px 0 0 rgba(0,0,0,0.2);
border-radius: .5em;
}
div.code-toolbar > .toolbar a:hover,
div.code-toolbar > .toolbar a:focus,
div.code-toolbar > .toolbar button:hover,
div.code-toolbar > .toolbar button:focus,
div.code-toolbar > .toolbar span:hover,
div.code-toolbar > .toolbar span:focus {
color: inherit;
text-decoration: none;
}
================================================
FILE: assets/vendor/prismjs/plugins/unescaped-markup/prism-unescaped-markup.css
================================================
/* Fallback, in case JS does not run, to ensure the code is at least visible */
[class*='lang-'] script[type='text/plain'],
[class*='language-'] script[type='text/plain'],
script[type='text/plain'][class*='lang-'],
script[type='text/plain'][class*='language-'] {
display: block;
font: 100% Consolas, Monaco, monospace;
white-space: pre;
overflow: auto;
}
================================================
FILE: assets/vendor/prismjs/plugins/wpd/prism-wpd.css
================================================
code[class*="language-"] a[href],
pre[class*="language-"] a[href] {
cursor: help;
text-decoration: none;
}
code[class*="language-"] a[href]:hover,
pre[class*="language-"] a[href]:hover {
cursor: help;
text-decoration: underline;
}
================================================
FILE: assets/vendor/prismjs/prism.js
================================================
/* **********************************************
Begin prism-core.js
********************************************** */
var _self = (typeof window !== 'undefined')
? window // if in browser
: (
(typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
? self // if in worker
: {} // if in node js
);
/**
* Prism: Lightweight, robust, elegant syntax highlighting
* MIT license http://www.opensource.org/licenses/mit-license.php/
* @author Lea Verou http://lea.verou.me
*/
var Prism = (function(){
// Private helper vars
var lang = /\blang(?:uage)?-([\w-]+)\b/i;
var uniqueId = 0;
var _ = _self.Prism = {
manual: _self.Prism && _self.Prism.manual,
disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
util: {
encode: function (tokens) {
if (tokens instanceof Token) {
return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias);
} else if (_.util.type(tokens) === 'Array') {
return tokens.map(_.util.encode);
} else {
return tokens.replace(/&/g, '&').replace(/ text.length) {
// Something went terribly wrong, ABORT, ABORT!
return;
}
if (str instanceof Token) {
continue;
}
if (greedy && i != strarr.length - 1) {
pattern.lastIndex = pos;
var match = pattern.exec(text);
if (!match) {
break;
}
var from = match.index + (lookbehind ? match[1].length : 0),
to = match.index + match[0].length,
k = i,
p = pos;
for (var len = strarr.length; k < len && (p < to || (!strarr[k].type && !strarr[k - 1].greedy)); ++k) {
p += strarr[k].length;
// Move the index i to the element in strarr that is closest to from
if (from >= p) {
++i;
pos = p;
}
}
// If strarr[i] is a Token, then the match starts inside another Token, which is invalid
if (strarr[i] instanceof Token) {
continue;
}
// Number of tokens to delete and replace with the new match
delNum = k - i;
str = text.slice(pos, p);
match.index -= pos;
} else {
pattern.lastIndex = 0;
var match = pattern.exec(str),
delNum = 1;
}
if (!match) {
if (oneshot) {
break;
}
continue;
}
if(lookbehind) {
lookbehindLength = match[1] ? match[1].length : 0;
}
var from = match.index + lookbehindLength,
match = match[0].slice(lookbehindLength),
to = from + match.length,
before = str.slice(0, from),
after = str.slice(to);
var args = [i, delNum];
if (before) {
++i;
pos += before.length;
args.push(before);
}
var wrapped = new Token(token, inside? _.tokenize(match, inside) : match, alias, match, greedy);
args.push(wrapped);
if (after) {
args.push(after);
}
Array.prototype.splice.apply(strarr, args);
if (delNum != 1)
_.matchGrammar(text, strarr, grammar, i, pos, true, token);
if (oneshot)
break;
}
}
}
},
tokenize: function(text, grammar, language) {
var strarr = [text];
var rest = grammar.rest;
if (rest) {
for (var token in rest) {
grammar[token] = rest[token];
}
delete grammar.rest;
}
_.matchGrammar(text, strarr, grammar, 0, 0, false);
return strarr;
},
hooks: {
all: {},
add: function (name, callback) {
var hooks = _.hooks.all;
hooks[name] = hooks[name] || [];
hooks[name].push(callback);
},
run: function (name, env) {
var callbacks = _.hooks.all[name];
if (!callbacks || !callbacks.length) {
return;
}
for (var i=0, callback; callback = callbacks[i++];) {
callback(env);
}
}
}
};
var Token = _.Token = function(type, content, alias, matchedStr, greedy) {
this.type = type;
this.content = content;
this.alias = alias;
// Copy of the full string this token was created from
this.length = (matchedStr || "").length|0;
this.greedy = !!greedy;
};
Token.stringify = function(o, language, parent) {
if (typeof o == 'string') {
return o;
}
if (_.util.type(o) === 'Array') {
return o.map(function(element) {
return Token.stringify(element, language, o);
}).join('');
}
var env = {
type: o.type,
content: Token.stringify(o.content, language, parent),
tag: 'span',
classes: ['token', o.type],
attributes: {},
language: language,
parent: parent
};
if (o.alias) {
var aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias];
Array.prototype.push.apply(env.classes, aliases);
}
_.hooks.run('wrap', env);
var attributes = Object.keys(env.attributes).map(function(name) {
return name + '="' + (env.attributes[name] || '').replace(/"/g, '"') + '"';
}).join(' ');
return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + (attributes ? ' ' + attributes : '') + '>' + env.content + '' + env.tag + '>';
};
if (!_self.document) {
if (!_self.addEventListener) {
// in Node.js
return _self.Prism;
}
if (!_.disableWorkerMessageHandler) {
// In worker
_self.addEventListener('message', function (evt) {
var message = JSON.parse(evt.data),
lang = message.language,
code = message.code,
immediateClose = message.immediateClose;
_self.postMessage(_.highlight(code, _.languages[lang], lang));
if (immediateClose) {
_self.close();
}
}, false);
}
return _self.Prism;
}
//Get current script and highlight
var script = document.currentScript || [].slice.call(document.getElementsByTagName("script")).pop();
if (script) {
_.filename = script.src;
if (!_.manual && !script.hasAttribute('data-manual')) {
if(document.readyState !== "loading") {
if (window.requestAnimationFrame) {
window.requestAnimationFrame(_.highlightAll);
} else {
window.setTimeout(_.highlightAll, 16);
}
}
else {
document.addEventListener('DOMContentLoaded', _.highlightAll);
}
}
}
return _self.Prism;
})();
if (typeof module !== 'undefined' && module.exports) {
module.exports = Prism;
}
// hack for components to work correctly in node.js
if (typeof global !== 'undefined') {
global.Prism = Prism;
}
/* **********************************************
Begin prism-markup.js
********************************************** */
Prism.languages.markup = {
'comment': //,
'prolog': /<\?[\s\S]+?\?>/,
'doctype': //i,
'cdata': //i,
'tag': {
pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,
greedy: true,
inside: {
'tag': {
pattern: /^<\/?[^\s>\/]+/i,
inside: {
'punctuation': /^<\/?/,
'namespace': /^[^\s>\/:]+:/
}
},
'attr-value': {
pattern: /=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,
inside: {
'punctuation': [
/^=/,
{
pattern: /(^|[^\\])["']/,
lookbehind: true
}
]
}
},
'punctuation': /\/?>/,
'attr-name': {
pattern: /[^\s>\/]+/,
inside: {
'namespace': /^[^\s>\/:]+:/
}
}
}
},
'entity': /?[\da-z]{1,8};/i
};
Prism.languages.markup['tag'].inside['attr-value'].inside['entity'] =
Prism.languages.markup['entity'];
// Plugin to make entity title show the real entity, idea by Roman Komarov
Prism.hooks.add('wrap', function(env) {
if (env.type === 'entity') {
env.attributes['title'] = env.content.replace(/&/, '&');
}
});
Prism.languages.xml = Prism.languages.markup;
Prism.languages.html = Prism.languages.markup;
Prism.languages.mathml = Prism.languages.markup;
Prism.languages.svg = Prism.languages.markup;
/* **********************************************
Begin prism-css.js
********************************************** */
Prism.languages.css = {
'comment': /\/\*[\s\S]*?\*\//,
'atrule': {
pattern: /@[\w-]+?.*?(?:;|(?=\s*\{))/i,
inside: {
'rule': /@[\w-]+/
// See rest below
}
},
'url': /url\((?:(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,
'selector': /[^{}\s][^{};]*?(?=\s*\{)/,
'string': {
pattern: /("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
greedy: true
},
'property': /[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,
'important': /\B!important\b/i,
'function': /[-a-z0-9]+(?=\()/i,
'punctuation': /[(){};:]/
};
Prism.languages.css['atrule'].inside.rest = Prism.languages.css;
if (Prism.languages.markup) {
Prism.languages.insertBefore('markup', 'tag', {
'style': {
pattern: /(
================================================
FILE: logout.php
================================================
================================================
FILE: profile.php
================================================
================================================
FILE: reports.php
================================================
prepare("SELECT id, name, tools, dataHour FROM reports ORDER BY dataHour DESC;");
$sql->execute();
$resultados = $sql->fetchAll(PDO::FETCH_ASSOC);
// FOREACH BEGINS
foreach ($resultados as $resultado) {
$id = $resultado['id'];
$name = $resultado['name'];
$tools = $resultado['tools'];
$command = $resultado['command'];
$output = $resultado['output'];
$solution = $resultado['solution'];
$dataOld = $resultado['dataHour'];
$dataHour = date ("d F Y - H:i", strtotime($dataOld));
?>
+ Show details" ?>
Delete" ?>
================================================
FILE: run.php
================================================
login($user, $password)) {
echo
"
Error! Connection to operating system failed!
×
";
} else {
// Get all the inputs firt
for ($i = 0; sizeof($arrayInputs) > $i; $i++) {
$cmd = $cmd . " " . $arrayInputs[$i][0] . " " . $arrayInputs[$i][1];
}
for ($i = 0; sizeof($arrayCheckbox) > $i; $i++) {
$cmd = $cmd . " " . $arrayCheckbox[$i];
}
$run = $command . " " . $cmd . " " . $target;
echo "
How to fix this?
We separate some tips exclusively for you.
Let's fix this!
";
echo "