Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 11f3271a52 | |||
| 8ded53c1de | |||
| 434699bf23 | |||
| 5e5d81dd86 | |||
| f8f5c923dd | |||
| 93c860e8e5 | |||
| 78223532ce | |||
| 9fc59562a1 | |||
| 045c117dbb | |||
| eb7b25ae17 | |||
| edd9a72c0e | |||
| 9046dbf244 | |||
| 5c7418cf36 | |||
| 61bddad2ea | |||
| 30a532d38c | |||
| 212733afbf | |||
| 33ebb52b56 | |||
| ed5573e806 |
+2
-4
@@ -1,6 +1,4 @@
|
||||
*.pyc
|
||||
*.o
|
||||
*.so
|
||||
other/.lein-deps-sum
|
||||
other/classes
|
||||
other/lib
|
||||
wsproxy
|
||||
*.DS_Store
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
Changes
|
||||
=======
|
||||
|
||||
0.1.0
|
||||
-----------------
|
||||
|
||||
* Initial versioned release.
|
||||
|
||||
+8
-8
@@ -1,11 +1,11 @@
|
||||
websockify is licensed under the LGPL version 3 (see docs/LICENSE.GPL-3 and
|
||||
noVNC is licensed under the LGPL version 3 (see docs/LICENSE.GPL-3 and
|
||||
docs/LICENSE.LGPL-3) with the following exceptions:
|
||||
|
||||
include/base64.js : Choice of MIT 1.1, GPL-2 or LGPL-2.1
|
||||
|
||||
include/web-socket-js/ : New BSD license. Source code at
|
||||
https://github.com/gimite/web-socket-js
|
||||
include/as3crypto_patched/ : various BSD style licenses
|
||||
|
||||
include/base64.js : Dual GPL-2 or LGPL-2.1
|
||||
|
||||
incluee/des.js : Various BSD style licenses
|
||||
|
||||
include/web-socket.js/ : New BSD license
|
||||
|
||||
other/kumina.c : Simplified BSD license (2 clause).
|
||||
Original source at
|
||||
https://github.com/kumina/wsproxy
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
include CHANGES.txt *.py README.md LICENSE.txt
|
||||
@@ -1,11 +0,0 @@
|
||||
TARGETS=rebind.so
|
||||
CFLAGS += -fPIC
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
rebind.so: rebind.o
|
||||
$(CC) $(LDFLAGS) $^ -shared -fPIC -ldl -o $@
|
||||
|
||||
clean:
|
||||
rm -f rebind.o rebind.so
|
||||
|
||||
@@ -1,155 +1,242 @@
|
||||
## websockify: WebSockets support for any application/server
|
||||
|
||||
websockify was formerly named wsproxy and was part of the
|
||||
[noVNC](https://github.com/kanaka/noVNC) project.
|
||||
|
||||
At the most basic level, websockify just translates WebSockets traffic
|
||||
to normal socket traffic. Websockify accepts the WebSockets handshake,
|
||||
parses it, and then begins forwarding traffic between the client and
|
||||
the target in both directions.
|
||||
|
||||
### WebSockets binary data
|
||||
|
||||
Websockify supports all versions of the WebSockets protocol (Hixie and
|
||||
HyBI). The older Hixie versions of the protocol only support UTF-8
|
||||
text payloads. In order to transport binary data over UTF-8 an
|
||||
encoding must used to encapsulate the data within UTF-8. Websockify
|
||||
uses base64 to encode all traffic to and from the client. This does
|
||||
not affect the data between websockify and the server.
|
||||
|
||||
### Encrypted WebSocket connections (wss://)
|
||||
|
||||
To encrypt the traffic using the WebSocket 'wss://' URI scheme you
|
||||
need to generate a certificate for websockify to load. By default websockify
|
||||
loads a certificate file name `self.pem` but the `--cert=CERT` option can
|
||||
override the file name. You can generate a self-signed certificate using
|
||||
openssl. When asked for the common name, use the hostname of the server where
|
||||
the proxy will be running:
|
||||
|
||||
```
|
||||
openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
|
||||
```
|
||||
## noVNC: HTML5 VNC Client
|
||||
|
||||
|
||||
### Websock Javascript library
|
||||
### Description
|
||||
|
||||
noVNC is a VNC client implemented using HTML5 technologies,
|
||||
specifically Canvas and WebSockets (supports 'wss://' encryption).
|
||||
|
||||
For browsers that do not have builtin WebSockets support, the project
|
||||
includes [web-socket-js](http://github.com/gimite/web-socket-js),
|
||||
a WebSockets emulator using Adobe Flash .
|
||||
|
||||
In addition, [as3crypto](http://github.com/lyokato/as3crypto_patched)
|
||||
has been added to web-socket-js to implement WebSockets SSL/TLS
|
||||
encryption, i.e. the "wss://" URI scheme.
|
||||
|
||||
Special thanks to [Sentry Data Systems](http://www.sentryds.com) for
|
||||
sponsoring ongoing development of this project (and for employing me).
|
||||
|
||||
Notable commits, announcements and news are posted to
|
||||
@<a href="http://www.twitter.com/noVNC">noVNC</a>
|
||||
|
||||
|
||||
The `include/websock.js` Javascript library library provides a Websock
|
||||
object that is similar to the standard WebSocket object but Websock
|
||||
enables communication with raw TCP sockets (i.e. the binary stream)
|
||||
via websockify. This is accomplished by base64 encoding the data
|
||||
stream between Websock and websockify.
|
||||
### Screenshots
|
||||
|
||||
Websock has built-in receive queue buffering; the message event
|
||||
does not contain actual data but is simply a notification that
|
||||
there is new data available. Several rQ* methods are available to
|
||||
read binary data off of the receive queue.
|
||||
Running in Chrome before and after connecting:
|
||||
|
||||
The Websock API is documented on the [websock.js API wiki page](https://github.com/kanaka/websockify/wiki/websock.js)
|
||||
<img src="http://kanaka.github.com/noVNC/img/noVNC-1.jpg" width=400> <img src="http://kanaka.github.com/noVNC/img/noVNC-2.jpg" width=400>
|
||||
|
||||
See the "Wrap a Program" section below for an example of using Websock
|
||||
and websockify as a browser telnet client (`wstelnet.html`).
|
||||
See more screenshots <a href="http://kanaka.github.com/noVNC/screenshots.html">here</a>.
|
||||
|
||||
|
||||
### Additional websockify features
|
||||
### Requirements
|
||||
|
||||
These are not necessary for the basic operation.
|
||||
Unless you are using a VNC server with support for WebSockets
|
||||
connections (only my [fork of libvncserver](http://github.com/kanaka/libvncserver)
|
||||
currently), you need to use a WebSockets to TCP socket proxy. There is
|
||||
a python proxy included ('wsproxy'). One advantage of using the proxy
|
||||
is that it has builtin support for SSL/TLS encryption (i.e. "wss://").
|
||||
|
||||
* Daemonizing: When the `-D` option is specified, websockify runs
|
||||
in the background as a daemon process.
|
||||
There a few reasons why a proxy is required:
|
||||
|
||||
* SSL (the wss:// WebSockets URI): This is detected automatically by
|
||||
websockify by sniffing the first byte sent from the client and then
|
||||
wrapping the socket if the data starts with '\x16' or '\x80'
|
||||
(indicating SSL).
|
||||
1. WebSockets is not a pure socket protocol. There is an initial HTTP
|
||||
like handshake to allow easy hand-off by web servers and allow
|
||||
some origin policy exchange. Also, each WebSockets frame begins
|
||||
with 0 ('\x00') and ends with 255 ('\xff').
|
||||
|
||||
* Flash security policy: websockify detects flash security policy
|
||||
requests (again by sniffing the first packet) and answers with an
|
||||
appropriate flash security policy response (and then closes the
|
||||
port). This means no separate flash security policy server is needed
|
||||
for supporting the flash WebSockets fallback emulator.
|
||||
|
||||
* Session recording: This feature that allows recording of the traffic
|
||||
sent and received from the client to a file using the `--record`
|
||||
option.
|
||||
|
||||
* Mini-webserver: websockify can detect and respond to normal web
|
||||
requests on the same port as the WebSockets proxy and Flash security
|
||||
policy. This functionality is activate with the `--web DIR` option
|
||||
where DIR is the root of the web directory to serve.
|
||||
|
||||
* Wrap a program: see the "Wrap a Program" section below.
|
||||
2. Javascript itself does not have the ability to handle pure byte
|
||||
arrays. The python proxy encodes the data as base64 so that the
|
||||
Javascript client can decode the data as an integer array.
|
||||
|
||||
|
||||
### Implementations of websockify
|
||||
### Quick Start
|
||||
|
||||
The primary implementation of websockify is in python. There are
|
||||
several alternate implementations in other languages (C, Node.js,
|
||||
Clojure, Ruby) in the `other/` subdirectory (with varying levels of
|
||||
functionality).
|
||||
* Use the launch script to start a mini-webserver and the WebSockets
|
||||
proxy. The `--vnc` option is used to specify the location of
|
||||
a running VNC server:
|
||||
|
||||
In addition there are several other external projects that implement
|
||||
the websockify "protocol". See the alternate implementation [Feature
|
||||
Matrix](https://github.com/kanaka/websockify/wiki/Feature_Matrix) for
|
||||
more information.
|
||||
`./utils/launch.sh --vnc localhost:5901`
|
||||
|
||||
* Point your browser to the cut-and-paste URL that is output by the
|
||||
launch script. Enter a password if the VNC server has one
|
||||
configured. Hit the Connect button and enjoy!
|
||||
|
||||
|
||||
### Wrap a Program
|
||||
### Advanced usage
|
||||
|
||||
In addition to proxying from a source address to a target address
|
||||
(which may be on a different system), websockify has the ability to
|
||||
launch a program on the local system and proxy WebSockets traffic to
|
||||
a normal TCP port owned/bound by the program.
|
||||
* To encrypt the traffic using the WebSocket 'wss://' URI scheme you
|
||||
need to generate a certificate for the proxy to load. By default the
|
||||
proxy loads a certificate file name `self.pem` but the `--cert=CERT`
|
||||
option can override the file name. You can generate a self-signed
|
||||
certificate using openssl. When asked for the common name, use the
|
||||
hostname of the server where the proxy will be running:
|
||||
|
||||
The is accomplished with a small LD_PRELOAD library (`rebind.so`)
|
||||
which intercepts bind() system calls by the program. The specified
|
||||
port is moved to a new localhost/loopback free high port. websockify
|
||||
then proxies WebSockets traffic directed to the original port to the
|
||||
new (moved) port of the program.
|
||||
`openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem`
|
||||
|
||||
The program wrap mode is invoked by replacing the target with `--`
|
||||
followed by the program command line to wrap.
|
||||
* `tightvnc` provide a nice startup script that can be used to run
|
||||
a separate X desktop that is served by VNC. To install and run the
|
||||
server under Ubuntu you would do something like this:
|
||||
|
||||
`./websockify 2023 -- PROGRAM ARGS`
|
||||
`sudo apt-get install tightvncserver`
|
||||
|
||||
The `--wrap-mode` option can be used to indicate what action to take
|
||||
when the wrapped program exits or daemonizes.
|
||||
`vncserver :1`
|
||||
|
||||
Here is an example of using websockify to wrap the vncserver command
|
||||
(which backgrounds itself) for use with
|
||||
[noVNC](https://github.com/kanaka/noVNC):
|
||||
The VNC server will run in the background. The port that it runs
|
||||
on is the display number + 5900 (i.e. 5901 in the case above).
|
||||
|
||||
`./websockify 5901 --wrap-mode=ignore -- vncserver -geometry 1024x768 :1`
|
||||
* `x11vnc` can be used to share your current X desktop. Note that if
|
||||
you run noVNC on the X desktop you are connecting to via VNC you
|
||||
will get a neat hall of mirrors effect, but the the client and
|
||||
server will fight over the mouse.
|
||||
|
||||
Here is an example of wrapping telnetd (from krb5-telnetd).telnetd
|
||||
exits after the connection closes so the wrap mode is set to respawn
|
||||
the command:
|
||||
`sudo apt-get install x11vnc`
|
||||
|
||||
`sudo ./websockify 2023 --wrap-mode=respawn -- telnetd -debug 2023`
|
||||
`x11vnc -forever -display :0`
|
||||
|
||||
The `wstelnet.html` page demonstrates a simple WebSockets based telnet
|
||||
client.
|
||||
Without the `-forever` option, x11vnc will exit after the first
|
||||
disconnect. The `-display` option indicates the exiting X display to
|
||||
share. The port that it runs on is the display number + 5900 (i.e.
|
||||
5900 in the case above).
|
||||
|
||||
* To run the python proxy directly without using launch script (to
|
||||
pass additional options for example):
|
||||
|
||||
`./utils/wsproxy.py -f source_port target_addr:target_port`
|
||||
|
||||
`./utils/wsproxy.py -f 8787 localhost:5901`
|
||||
|
||||
* To run the mini python web server without the launch script:
|
||||
|
||||
`./utils/web.py PORT`
|
||||
|
||||
`./utils/web.py 8080`
|
||||
|
||||
* Point your web browser at http://localhost:8080/vnc.html
|
||||
(or whatever port you used above to run the web server). Specify the
|
||||
host and port where the proxy is running and the password that the
|
||||
vnc server is using (if any). Hit the Connect button.
|
||||
|
||||
|
||||
### Building the Python ssl module (for python 2.5 and older)
|
||||
### Browser Support
|
||||
|
||||
* Install the build dependencies. On Ubuntu use this command:
|
||||
In the following table Jaunty is Ubuntu 9.04 and WinXP is Windows XP.
|
||||
|
||||
`sudo aptitude install python-dev bluetooth-dev`
|
||||
#### Linux (Ubuntu 9.04)
|
||||
|
||||
* Download, build the ssl module and symlink to it:
|
||||
<table>
|
||||
<tr>
|
||||
<th>OS</th> <th>Browser</th>
|
||||
<th>Status</th>
|
||||
<th>Notes</th>
|
||||
</tr> <tr>
|
||||
<td>Jaunty</td> <td>Chrome 5.0.375.29</td>
|
||||
<td>Excellent</td>
|
||||
<td>Very fast. Native WebSockets.</td>
|
||||
</tr> <tr>
|
||||
<td>Jaunty</td> <td>Firefox 3.5</td>
|
||||
<td>Good</td>
|
||||
<td>Large full-color images are somewhat slow from web-socket-js overhead.</td>
|
||||
</tr> <tr>
|
||||
<td>Jaunty</td> <td>Firefox 3.0.17</td>
|
||||
<td>Fair</td>
|
||||
<td>Works fine but is slow.</td>
|
||||
</tr> <tr>
|
||||
<td>Jaunty</td> <td>Opera 10.60</td>
|
||||
<td>Poor</td>
|
||||
<td>web-socket-js problems, mouse/keyboard issues. See note 1</td>
|
||||
</tr> <tr>
|
||||
<td>Jaunty</td> <td>Arora 0.5</td>
|
||||
<td>Good</td>
|
||||
<td>Broken putImageData so large full-color images
|
||||
are slow. Uses web-socket-js.</td>
|
||||
</tr> <tr>
|
||||
<td>Jaunty</td> <td>Konqueror 4.2.2</td>
|
||||
<td><strong>Broken</strong></td>
|
||||
<td>web-socket-js never loads</td>
|
||||
</tr> <tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr> <tr>
|
||||
<td>WinXP</td> <td>Chrome 5.0.375.99</td>
|
||||
<td>Excellent</td>
|
||||
<td>Very fast. Native WebSockets.</td>
|
||||
</tr> <tr>
|
||||
<td>WinXP</td> <td>Firefox 3.0.19</td>
|
||||
<td>Good</td>
|
||||
<td>Some overhead from web-socket-js.</td>
|
||||
</tr> <tr>
|
||||
<td>WinXP</td> <td>Safari 5.0</td>
|
||||
<td>Fair</td>
|
||||
<td>Fast. Native WebSockets. Broken 'wss://' (SSL) - weird client header</td>
|
||||
</tr> <tr>
|
||||
<td>WinXP</td> <td>IE 6, 7, 8</td>
|
||||
<td><strong>Non-starter</strong></td>
|
||||
<td>No basic Canvas support. Javascript painfully slow.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
`cd websockify/`
|
||||
|
||||
`wget http://pypi.python.org/packages/source/s/ssl/ssl-1.15.tar.gz`
|
||||
* Note 1: Opera interacts poorly with web-socket-js. After two
|
||||
disconnects the browser tab or Flash often hang. Although Javascript
|
||||
is faster than Firefox 3.5, the high variability of web-socket-js
|
||||
performance results in overall performance being lower. Middle mouse
|
||||
clicks and keyboard events need some work to work properly under
|
||||
Opera. Also, Opera does not have support for setting the cursor
|
||||
style url to a data URI scheme, so cursor pseudo-encoding is
|
||||
disabled.
|
||||
|
||||
`tar xvzf ssl-1.15.tar.gz`
|
||||
|
||||
`cd ssl-1.15`
|
||||
### Integration
|
||||
|
||||
`make`
|
||||
The client is designed to be easily integrated with existing web
|
||||
structure and style.
|
||||
|
||||
`cd ../`
|
||||
At a minimum you must include the `vnc.js` and `default_controls.js`
|
||||
scripts and call DefaultControls.load(). For example:
|
||||
|
||||
`ln -sf ssl-1.15/build/lib.linux-*/ssl ssl`
|
||||
<head>
|
||||
<script src='include/vnc.js'></script>
|
||||
<script src="include/default_controls.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id='vnc'>Loading</div>
|
||||
|
||||
<script>
|
||||
window.onload = function () {
|
||||
DefaultControls.load('vnc');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
See `vnc.html` and `vnc_auto.html` for examples. The file
|
||||
`include/plain.css` has a list of stylable elements.
|
||||
|
||||
The `vnc.js` also includes other scripts within the `include`
|
||||
sub-directory. The `VNC_uri_prefix` variable can be use override the
|
||||
URL path to the `include` sub-directory.
|
||||
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
You will need console logging support in the browser. Recent Chrome
|
||||
and Opera versions have built in support. Firefox has a nice extension
|
||||
called "firebug" that gives console logging support.
|
||||
|
||||
First, load the noVNC page with `logging=debug` added to the query string.
|
||||
For example `vnc.html?logging=debug`.
|
||||
|
||||
Then, activate the console logger in your browser. With Chrome it can
|
||||
be activate using Ctrl+Shift+J and then switching to the "Console"
|
||||
tab. With firefox+firebug, it can be activated using Ctrl+F12.
|
||||
|
||||
Now reproduce the problem. The console log output will give more
|
||||
information about what is going wrong and where in the code the
|
||||
problem is located.
|
||||
|
||||
If you file a issue/bug, it is very helpful for me to have the last
|
||||
page of console output leading up the problem in the issue report.
|
||||
Other helpful issue/bug information: browser version, OS version,
|
||||
noVNC git version, and VNC server name/version.
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
-----------------------------------
|
||||
Windows noVNC Websockify Service
|
||||
-----------------------------------
|
||||
|
||||
The "noVNC Websocket Service.exe" file is a windows service wrapper created with Visual Studio 2010 to create a windows service to start stop the noVNC Websocket Server. All files used to create the wrapper can be found in 'noVNC Websocket Service Project' folder.
|
||||
|
||||
To download the precompiled executables please grab the zip in the downloads section of websockify project:
|
||||
https://github.com/kanaka/websockify
|
||||
|
||||
---------------------------
|
||||
Installation
|
||||
---------------------------
|
||||
|
||||
1. This service requires websockify.exe be in the same directory. Instructions on how to compile websockify python script as a windows executable can be found here:
|
||||
https://github.com/kanaka/noVNC/wiki/Compiling-Websockify-to-Windows-Executable
|
||||
|
||||
2.To add this service to a Windows PC you need to run the commandline as administrator and then run this line:
|
||||
|
||||
sc create "noVNC Websocket Server" binPath= "PATH TO noVNC eg C:\noVNC\utils\Windows\Websocket Service.exe" DisplayName= "noVNC Websocket Server"
|
||||
|
||||
3 .Once this is run you will be able to access the service via Control Panel > Admin Tools > Services. In here you can specify whether you want the service to run automatically and start at stop the service.
|
||||
|
||||
---------------------------
|
||||
Configuration
|
||||
---------------------------
|
||||
The file noVNCConfig.ini must be in the same directory as "noVNC Websocket Service.exe".
|
||||
|
||||
This file contains a single line which is the websockify.exe statup arguements. An example is:
|
||||
192.168.0.1:5901 192.168.0.1:5900
|
||||
|
||||
All websockify supported arguements will work if added here.
|
||||
|
||||
---------------------------
|
||||
Deletion
|
||||
---------------------------
|
||||
|
||||
You can delete the service at any time by running the commandline as admin and using this command:
|
||||
sc delete "noVNC Websocket Server".
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.ServiceProcess;
|
||||
using System.Text;
|
||||
|
||||
namespace MELT_Command_Websocket
|
||||
{
|
||||
static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
static void Main()
|
||||
{
|
||||
ServiceBase[] ServicesToRun;
|
||||
ServicesToRun = new ServiceBase[]
|
||||
{
|
||||
new Service1()
|
||||
};
|
||||
ServiceBase.Run(ServicesToRun);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
namespace MELT_Command_Websocket
|
||||
{
|
||||
partial class ProjectInstaller
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
|
||||
this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
|
||||
//
|
||||
// serviceProcessInstaller1
|
||||
//
|
||||
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.NetworkService;
|
||||
this.serviceProcessInstaller1.Installers.AddRange(new System.Configuration.Install.Installer[] {
|
||||
this.serviceInstaller1});
|
||||
this.serviceProcessInstaller1.Password = null;
|
||||
this.serviceProcessInstaller1.Username = null;
|
||||
//
|
||||
// serviceInstaller1
|
||||
//
|
||||
this.serviceInstaller1.Description = "noVNC Websocket Service";
|
||||
this.serviceInstaller1.DisplayName = "noVNC Websocket Service";
|
||||
this.serviceInstaller1.ServiceName = "noVNC Websocket Service";
|
||||
this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
|
||||
//
|
||||
// ProjectInstaller
|
||||
//
|
||||
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
|
||||
this.serviceProcessInstaller1});
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
|
||||
private System.ServiceProcess.ServiceInstaller serviceInstaller1;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Configuration.Install;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace MELT_Command_Websocket
|
||||
{
|
||||
[RunInstaller(true)]
|
||||
public partial class ProjectInstaller : System.Configuration.Install.Installer
|
||||
{
|
||||
public ProjectInstaller()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="serviceProcessInstaller1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 56</value>
|
||||
</metadata>
|
||||
<metadata name="serviceInstaller1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>196, 17</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MELT Command Websocket")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("MELT Command Websocket")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("5ab831cb-6852-4ce1-849c-b26725b0e10b")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,37 +0,0 @@
|
||||
namespace MELT_Command_Websocket
|
||||
{
|
||||
partial class Service1
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
this.ServiceName = "Service1";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.ServiceProcess;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace MELT_Command_Websocket
|
||||
{
|
||||
public partial class Service1 : ServiceBase
|
||||
{
|
||||
Process websockify;
|
||||
public Service1()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnStart(string[] args)
|
||||
{
|
||||
|
||||
string configpath = AppDomain.CurrentDomain.BaseDirectory + "\\noVNCConfig.ini";
|
||||
string sockifypath = AppDomain.CurrentDomain.BaseDirectory + "\\websockify.exe";
|
||||
//Load commandline arguements from config file.
|
||||
StreamReader streamReader = new StreamReader(configpath);
|
||||
string arguements = streamReader.ReadLine();
|
||||
streamReader.Close();
|
||||
|
||||
//Start websockify.
|
||||
websockify = System.Diagnostics.Process.Start(sockifypath, arguements);
|
||||
}
|
||||
|
||||
protected override void OnStop()
|
||||
{
|
||||
//Service stopped. Close websockify.
|
||||
websockify.Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{6B86AE7B-6BBD-4E74-8802-5995E8B6D27D}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>noVNC_Websocket_Service</RootNamespace>
|
||||
<AssemblyName>noVNC Websocket Service</AssemblyName>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration.Install" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.ServiceProcess" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ProjectInstaller.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ProjectInstaller.Designer.cs">
|
||||
<DependentUpon>ProjectInstaller.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Service1.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Service1.Designer.cs">
|
||||
<DependentUpon>Service1.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="ProjectInstaller.resx">
|
||||
<DependentUpon>ProjectInstaller.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,20 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "noVNC Websocket", "noVNC Websocket.csproj", "{6B86AE7B-6BBD-4E74-8802-5995E8B6D27D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{6B86AE7B-6BBD-4E74-8802-5995E8B6D27D}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{6B86AE7B-6BBD-4E74-8802-5995E8B6D27D}.Debug|x86.Build.0 = Debug|x86
|
||||
{6B86AE7B-6BBD-4E74-8802-5995E8B6D27D}.Release|x86.ActiveCfg = Release|x86
|
||||
{6B86AE7B-6BBD-4E74-8802-5995E8B6D27D}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,9 +1,51 @@
|
||||
- Go implementation
|
||||
Short Term:
|
||||
|
||||
- Support multiple targets that are selected by the path line. Some
|
||||
sort of wildcarding of ports too.
|
||||
- Proper Javascript namespacing for Canvas and RFB (using function for
|
||||
true local variables and functions).
|
||||
|
||||
- Support SSL targets too.
|
||||
- Timing delta between frames in proxy record log, for playback
|
||||
support (for demo and test).
|
||||
|
||||
- wstelnet: support CSI L and CSI M
|
||||
- Playback/demo on website.
|
||||
|
||||
- Test on IE 9 preview 3.
|
||||
|
||||
- Fix cursor URI detection in Arora:
|
||||
- allows data URI, but doesn't actually work
|
||||
|
||||
|
||||
Medium Term:
|
||||
|
||||
- Viewport support
|
||||
|
||||
- Status bar menu/buttons:
|
||||
- Explanatory hover text over buttons
|
||||
|
||||
- Configuration menu:
|
||||
- Tunable: speed vs. bandwidth selection
|
||||
- Tunable: CPU use versus latency.
|
||||
- shared mode
|
||||
- Scaling
|
||||
|
||||
- Keyboard menu:
|
||||
- Ctrl Lock, Alt Lock, SysRq Lock
|
||||
- Highlight menu icon when keys are locked
|
||||
|
||||
- Clipboard button -> popup:
|
||||
- text, clear and send buttons
|
||||
|
||||
|
||||
Longer Term:
|
||||
|
||||
- Implement UI option for VNC shared mode.
|
||||
|
||||
- Get web-socket-js RFC2817 proxying working again.
|
||||
|
||||
- Implement tight and ZRLE encoding
|
||||
|
||||
- Support for Spice protocol.
|
||||
|
||||
- Consider RDP protocol.
|
||||
|
||||
- Consider NX protocol.
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
Manual setup:
|
||||
|
||||
DATA="echo \'<cross-domain-policy><allow-access-from domain=\\\"*\\\" to-ports=\\\"*\\\" /></cross-domain-policy>\'"
|
||||
/usr/bin/socat -T 1 TCP-L:843,reuseaddr,fork,crlf SYSTEM:"$DATA"
|
||||
@@ -1,114 +0,0 @@
|
||||
This data is raw copy from the latency tester set to send a frame with
|
||||
a little over 2000 KB of data every 10ms.
|
||||
|
||||
The number of packets sent and received is just a visual counter and
|
||||
is just the total when I chose to stop the test (around 3000 or so
|
||||
packets).
|
||||
|
||||
The latency measure are from the point the packet was sent to when it
|
||||
was received back again in milliseconds. One notable data point
|
||||
missing from this is how long it actually took for the client to send
|
||||
3000 packets because sending large packets can put load on the browser
|
||||
and it may be a lot longer than 10ms before the timer event to
|
||||
send the next packet fires. So even with low latency numbers, the
|
||||
actual send rate may be fairly low because sending the WebSockets
|
||||
frames is impacting the performance of the browser in general.
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
|
||||
Native WebSockets implementations, 2000 byte payload, 10ms delay
|
||||
|
||||
Chrome 8.0.552 - native WebSockets
|
||||
Packets sent: 2998
|
||||
Packets Received: 2998
|
||||
Average Latency: 1.84
|
||||
40 Frame Running Average Latency: 1.90
|
||||
Minimum Latency: 1.00
|
||||
Maximum Latency: 10.00
|
||||
|
||||
firefox 4.0b9 - WebSockets enabled
|
||||
Packets sent: 3011
|
||||
Packets Received: 3011
|
||||
Average Latency: 6.45
|
||||
40 Frame Running Average Latency: 6.08
|
||||
Minimum Latency: 5.00
|
||||
Maximum Latency: 119.00
|
||||
|
||||
Opera 11 - WebSockets enabled
|
||||
Packets sent: 3065
|
||||
Packets Received: 3064
|
||||
Average Latency: 9.56
|
||||
40 Frame Running Average Latency: 8.15
|
||||
Minimum Latency: 4.00
|
||||
Maximum Latency: 53.00
|
||||
|
||||
------------------------------------------------------------
|
||||
|
||||
New web-socket-js (20f837425d4), 2000 byte payload, 10ms delay
|
||||
|
||||
firefox 4.0b9 - no WebSockets
|
||||
Packets sent: 3088
|
||||
Packets Received: 3087
|
||||
Average Latency: 16.71
|
||||
40 Frame Running Average Latency: 16.80
|
||||
Minimum Latency: 7.00
|
||||
Maximum Latency: 75.00
|
||||
|
||||
- First 1000 sent in 13 seconds
|
||||
- Second 1000 sent in 12 seconds
|
||||
- Third 1000 sent in 12 seconds
|
||||
|
||||
firefox 3.6.10 - no WebSockets
|
||||
Packets sent: 3100
|
||||
Packets Received: 3099
|
||||
Average Latency: 17.32
|
||||
40 Frame Running Average Latency: 16.73
|
||||
Minimum Latency: 6.00
|
||||
Maximum Latency: 72.00
|
||||
|
||||
Opera 11 - no WebSockets
|
||||
Packets sent: 3007
|
||||
Packets Received: 3007
|
||||
Average Latency: 465.91
|
||||
40 Frame Running Average Latency: 147.95
|
||||
Minimum Latency: 12.00
|
||||
Maximum Latency: 9143.00
|
||||
|
||||
- average starts at around 28ms
|
||||
- time for each 500 packets: 13s, 16s, 25s, 37s, 50s, 72s
|
||||
- also start seeing sent, receive lags around 1200 packets
|
||||
|
||||
---------------------------------------------------------------
|
||||
|
||||
Old web-socket-js (9e7663771), 2000 byte payload, 10ms delay
|
||||
|
||||
firefox 4.0b9 - no WebSockets
|
||||
Packets sent: 3024
|
||||
Packets Received: 3020
|
||||
Average Latency: 80.59
|
||||
40 Frame Running Average Latency: 60.15
|
||||
Minimum Latency: 10.00
|
||||
Maximm Latency: 348.00
|
||||
|
||||
|
||||
firefox 3.6.10 - no WebSockets
|
||||
Packets sent: 2777
|
||||
Packets Received: 2775
|
||||
Average Latency: 34.89
|
||||
40 Frame Running Average Latency: 24.50
|
||||
Minimum Latency: 10.00
|
||||
Maximum Latency: 208.00
|
||||
|
||||
|
||||
Opera 11 - no Websockets
|
||||
Packets sent: 3012
|
||||
Packets Received: 3011
|
||||
Average Latency: 380.87
|
||||
40 Frame Running Average Latency: 341.90
|
||||
Minimum Latency: 28.00
|
||||
Maximum Latency: 2175.00
|
||||
|
||||
- average starts at around 290ms
|
||||
- time for each 1000 packets: 23s, 38s, 65s
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
New tight PNG protocol:
|
||||
http://wiki.qemu.org/VNC_Tight_PNG
|
||||
http://xf.iksaif.net/blog/index.php?post/2010/06/14/QEMU:-Tight-PNG-and-some-profiling
|
||||
|
||||
RFB protocol and extensions:
|
||||
http://tigervnc.org/cgi-bin/rfbproto
|
||||
|
||||
Canvas Browser Compatibility:
|
||||
http://philip.html5.org/tests/canvas/suite/tests/results.html
|
||||
|
||||
WebSockets API standard:
|
||||
http://www.whatwg.org/specs/web-apps/current-work/complete.html#websocket
|
||||
http://dev.w3.org/html5/websockets/
|
||||
http://www.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-00.txt
|
||||
|
||||
Browser Keyboard Events detailed:
|
||||
http://unixpapa.com/js/key.html
|
||||
|
||||
ActionScript (Flash) WebSocket implementation:
|
||||
http://github.com/gimite/web-socket-js
|
||||
|
||||
ActionScript (Flash) crypto/TLS library:
|
||||
http://code.google.com/p/as3crypto
|
||||
http://github.com/lyokato/as3crypto_patched
|
||||
|
||||
TLS Protocol:
|
||||
http://en.wikipedia.org/wiki/Transport_Layer_Security
|
||||
|
||||
Generate self-signed certificate:
|
||||
http://docs.python.org/dev/library/ssl.html#certificates
|
||||
|
||||
Cursor appearance/style (for Cursor pseudo-encoding):
|
||||
http://en.wikipedia.org/wiki/ICO_(file_format)
|
||||
http://www.daubnet.com/en/file-format-cur
|
||||
https://developer.mozilla.org/en/Using_URL_values_for_the_cursor_property
|
||||
|
||||
|
||||
Related projects:
|
||||
|
||||
guacamole: http://guacamole.sourceforge.net/
|
||||
|
||||
- Web client, but Java servlet does pre-processing
|
||||
|
||||
jsvnc: http://code.google.com/p/jsvnc/
|
||||
|
||||
- No releases
|
||||
|
||||
webvnc: http://code.google.com/p/webvnc/
|
||||
|
||||
- Jetty web server gateway, no updates since April 2008.
|
||||
|
||||
RealVNC Java applet: http://www.realvnc.com/support/javavncviewer.html
|
||||
|
||||
- Java applet
|
||||
|
||||
Flashlight-VNC: http://www.wizhelp.com/flashlight-vnc/
|
||||
|
||||
- Adobe Flash implementation
|
||||
|
||||
FVNC: http://osflash.org/fvnc
|
||||
|
||||
- Adbove Flash implementation
|
||||
|
||||
CanVNC: http://canvnc.sourceforge.net/
|
||||
|
||||
- HTML client with REST to VNC python proxy. Mostly vapor.
|
||||
+32
-5
@@ -4,12 +4,39 @@ There is an included flash object (web-socket-js) that is used to
|
||||
emulate websocket support on browsers without websocket support
|
||||
(currently only Chrome has WebSocket support).
|
||||
|
||||
The performance on Chrome is great. It only takes about 150ms on my
|
||||
system to render a complete 800x600 hextile frame. Most updates are
|
||||
partial or use copyrect which is much faster.
|
||||
|
||||
When using the flash websocket emulator, packets event aren't always
|
||||
delivered in order. This may be a bug in the way I'm using the
|
||||
FABridge interface. Or a bug in FABridge itself, or just a browser
|
||||
event delivery issue. Anyways, to get around this problem, when the
|
||||
flash emulator is being used, the client issues the WebSocket GET
|
||||
request with the "seq_num" variable. This switches on in-band sequence
|
||||
numbering of the packets in the proxy, and the client has a queue of
|
||||
out-of-order packets (20 deep currently) that it uses to re-order.
|
||||
Gross!
|
||||
|
||||
The performance on firefox 3.5 is usable. It takes 2.3 seconds to
|
||||
render a 800x600 hextile frame on my system (the initial connect).
|
||||
Once the initial first update is done though, it's quite usable (as
|
||||
above, most updates are partial or copyrect). I haven't tested firefox
|
||||
3.7 yet, it might be a lot faster.
|
||||
|
||||
Opera sucks big time. The flash websocket emulator fails to deliver as
|
||||
many as 40% of packet events when used on Opera. It may or not be
|
||||
Opera's fault, but something goes badly wrong at the FABridge
|
||||
boundary.
|
||||
|
||||
Javascript doesn't have a bytearray type, so what you get out of
|
||||
a WebSocket object is just Javascript strings. Javascript has UTF-16
|
||||
unicode strings and anything sent through the WebSocket gets converted
|
||||
to UTF-8 and vice-versa. So, one additional (and necessary) function
|
||||
of wsproxy is base64 encoding/decoding what is sent to/from the
|
||||
browser.
|
||||
a WebSocket object is just Javascript strings. I believe that
|
||||
Javascript has UTF-16 unicode strings and anything sent through the
|
||||
WebSocket gets converted to UTF-8 and vice-versa. So, one additional
|
||||
(and necessary) function of the proxy is base64 encoding/decoding what
|
||||
is sent to/from the browser. Another option that I want to explore is
|
||||
UTF-8 encoding in the proxy.
|
||||
|
||||
|
||||
Building web-socket-js emulator:
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
Description of the WebSockets to TCP Proxy
|
||||
|
||||
|
||||
At the most basic level, the proxy just translates WebSockets traffic
|
||||
to normal socket traffic. The proxy accepts the WebSockets header,
|
||||
parses it, and then begins forwarding traffic between the client and
|
||||
the target in both directions. At a minimum the proxy needs to base64
|
||||
encode traffic destined for the client and decode it coming from the
|
||||
client. Also, WebSockets traffic starts with '\0' (0) and ends with
|
||||
'\xff' (255) so that needs to be added/stripped by the proxy. There
|
||||
is a little bit of buffering you need to do in case the data from the
|
||||
client isn't a full WebSockets frame (i.e. doesn't end in 255).
|
||||
|
||||
|
||||
Other proxy features (that aren't necessary for the basic operation):
|
||||
|
||||
|
||||
SSL (the wss:// WebSockets URI):
|
||||
|
||||
This is detected automatically by the proxy by sniffing the first byte
|
||||
of the client's connection and then wrapping the socket if the data
|
||||
starts with '\x16' (indicating SSL).
|
||||
|
||||
|
||||
Sequence Numbering:
|
||||
|
||||
When the client doesn't have native WebSockets support in the browser
|
||||
(currently only Chrome and Safari 5), a flash emulator fallback is
|
||||
used. Unfortunately, when this is used, frame ordering is not 100%,
|
||||
so the GET URI in the initial handshake has "seq_num=1". This tells
|
||||
the proxy to add sequence numbers to every WebSockets frame so that
|
||||
the browser can reorder them.
|
||||
|
||||
|
||||
UTF-8 encoding:
|
||||
|
||||
In addition to the base64 encoding of the data, the proxy also
|
||||
supports UTF-8 encoding of the data (the native WebSockets encoding).
|
||||
However, in order to not burden the browser too much, the encoding
|
||||
doesn't use the full UTF-8 value space, but only uses the first 256
|
||||
values. This actually makes UTF-8 encoding slightly less space
|
||||
efficient than base64. Also, flash cannot handle byte arrays with 0's
|
||||
in them properly, so the values are actually 1-256 (rather than 0-255)
|
||||
and the browser does modulus 256 on the data. For these two reasons,
|
||||
base64 is the default and is indicated in the GET string by
|
||||
"base64=1".
|
||||
|
||||
|
||||
Flash security policy:
|
||||
|
||||
The proxy detects flash security policy requests (again by sniffing
|
||||
the first packet) and answers with an appropriate flash security
|
||||
policy response (and then closes the port). This means no separate
|
||||
flash security policy server is needed for supporting the flash
|
||||
WebSockets fallback emulator.
|
||||
|
||||
|
||||
Daemonizing:
|
||||
|
||||
The proxy also supports daemonizing (when the -f option is not
|
||||
specified).
|
||||
|
||||
|
||||
Record:
|
||||
|
||||
Finally, there is a debug feature that allows recording of the traffic
|
||||
sent and received from the client to a file (the --record option).
|
||||
@@ -1,7 +0,0 @@
|
||||
- Update setup.py and CHANGES.txt and commit
|
||||
- Create version tag and tarball from tag
|
||||
WVER=0.1.0
|
||||
git tag ${WVER}
|
||||
git archive --format=tar --prefix=websockify-${WVER}/ v${WVER} > websockify-${WVER}.tar
|
||||
gzip websockify-${WVER}.tar
|
||||
- Upload tarball to repo
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
5.1.1 ProtocolVersion: 12, 12 bytes
|
||||
|
||||
- Sent by server, max supported
|
||||
12 ascii - "RFB 003.008\n"
|
||||
- Response by client, version to use
|
||||
12 ascii - "RFB 003.003\n"
|
||||
|
||||
5.1.2 Authentication: >=4, [16, 4] bytes
|
||||
|
||||
- Sent by server
|
||||
CARD32 - authentication-scheme
|
||||
0 - connection failed
|
||||
CARD32 - length
|
||||
length - reason
|
||||
1 - no authentication
|
||||
|
||||
2 - VNC authentication
|
||||
16 CARD8 - challenge (random bytes)
|
||||
|
||||
- Response by client (if VNC authentication)
|
||||
16 CARD8 - client encrypts the challenge with DES, using user
|
||||
password as key, sends resulting 16 byte response
|
||||
|
||||
- Response by server (if VNC authentication)
|
||||
CARD32 - 0 - OK
|
||||
1 - failed
|
||||
2 - too-many
|
||||
|
||||
5.1.3 ClientInitialisation: 1 byte
|
||||
- Sent by client
|
||||
CARD8 - shared-flag, 0 exclusive, non-zero shared
|
||||
|
||||
5.1.4 ServerInitialisation: >=24 bytes
|
||||
- Sent by server
|
||||
CARD16 - framebuffer-width
|
||||
CARD16 - framebuffer-height
|
||||
16 byte PIXEL_FORMAT - server-pixel-format
|
||||
CARD8 - bits-per-pixel
|
||||
CARD8 - depth
|
||||
CARD8 - big-endian-flag, non-zero is big endian
|
||||
CARD8 - true-color-flag, non-zero then next 6 apply
|
||||
CARD16 - red-max
|
||||
CARD16 - green-max
|
||||
CARD16 - blue-max
|
||||
CARD8 - red-shift
|
||||
CARD8 - green-shift
|
||||
CARD8 - blue-shift
|
||||
3 bytes - padding
|
||||
CARD32 - name-length
|
||||
|
||||
CARD8[length] - name-string
|
||||
|
||||
|
||||
|
||||
Client to Server Messages:
|
||||
|
||||
5.2.1 SetPixelFormat: 20 bytes
|
||||
CARD8: 0 - message-type
|
||||
...
|
||||
|
||||
5.2.2 FixColourMapEntries: >=6 bytes
|
||||
CARD8: 1 - message-type
|
||||
...
|
||||
|
||||
5.2.3 SetEncodings: >=8 bytes
|
||||
CARD8: 2 - message-type
|
||||
CARD8 - padding
|
||||
CARD16 - numer-of-encodings
|
||||
|
||||
CARD32 - encoding-type in preference order
|
||||
0 - raw
|
||||
1 - copy-rectangle
|
||||
2 - RRE
|
||||
4 - CoRRE
|
||||
5 - hextile
|
||||
|
||||
5.2.4 FramebufferUpdateRequest (10 bytes)
|
||||
CARD8: 3 - message-type
|
||||
CARD8 - incremental (0 for full-update, non-zero for incremental)
|
||||
CARD16 - x-position
|
||||
CARD16 - y-position
|
||||
CARD16 - width
|
||||
CARD16 - height
|
||||
|
||||
|
||||
5.2.5 KeyEvent: 8 bytes
|
||||
CARD8: 4 - message-type
|
||||
CARD8 - down-flag
|
||||
2 bytes - padding
|
||||
CARD32 - key (X-Windows keysym values)
|
||||
|
||||
5.2.6 PointerEvent: 6 bytes
|
||||
CARD8: 5 - message-type
|
||||
CARD8 - button-mask
|
||||
CARD16 - x-position
|
||||
CARD16 - y-position
|
||||
|
||||
5.2.7 ClientCutText: >=9 bytes
|
||||
CARD8: 6 - message-type
|
||||
...
|
||||
|
||||
|
||||
Server to Client Messages:
|
||||
|
||||
5.3.1 FramebufferUpdate
|
||||
CARD8: 0 - message-type
|
||||
1 byte - padding
|
||||
CARD16 - number-of-rectangles
|
||||
|
||||
CARD16 - x-position
|
||||
CARD16 - y-position
|
||||
CARD16 - width
|
||||
CARD16 - height
|
||||
CARD16 - encoding-type:
|
||||
0 - raw
|
||||
1 - copy rectangle
|
||||
2 - RRE
|
||||
4 - CoRRE
|
||||
5 - hextile
|
||||
|
||||
raw:
|
||||
- width x height pixel values
|
||||
|
||||
copy rectangle:
|
||||
CARD16 - src-x-position
|
||||
CARD16 - src-y-position
|
||||
|
||||
RRE:
|
||||
CARD32 - N number-of-subrectangles
|
||||
Nxd bytes - background-pixel-value (d bits-per-pixel)
|
||||
|
||||
...
|
||||
|
||||
5.3.2 SetColourMapEntries (no support)
|
||||
CARD8: 1 - message-type
|
||||
...
|
||||
|
||||
5.3.3 Bell
|
||||
CARD8: 2 - message-type
|
||||
|
||||
5.3.4 ServerCutText
|
||||
CARD8: 3 - message-type
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,919 +0,0 @@
|
||||
// VT100.js -- a text terminal emulator in JavaScript with a ncurses-like
|
||||
// interface and a POSIX-like interface. (The POSIX-like calls are
|
||||
// implemented on top of the ncurses-like calls, not the other way round.)
|
||||
//
|
||||
// Released under the GNU LGPL v2.1, by Frank Bi <bi@zompower.tk>
|
||||
//
|
||||
// 2007-08-12 - refresh():
|
||||
// - factor out colour code to html_colours_()
|
||||
// - fix handling of A_REVERSE | A_DIM
|
||||
// - simplify initial <br /> output code
|
||||
// - fix underlining colour
|
||||
// - fix attron() not to turn off attributes
|
||||
// - decouple A_STANDOUT and A_BOLD
|
||||
// 2007-08-11 - getch() now calls refresh()
|
||||
// 2007-08-06 - Safari compat fix -- turn '\r' into '\n' for onkeypress
|
||||
// 2007-08-05 - Opera compat fixes for onkeypress
|
||||
// 2007-07-30 - IE compat fixes:
|
||||
// - change key handling code
|
||||
// - add <br />...<br /> so that 1st and last lines align
|
||||
// 2007-07-28 - change wrapping behaviour -- writing at the right edge no
|
||||
// longer causes the cursor to immediately wrap around
|
||||
// - add <b>...</b> to output to make A_STANDOUT stand out more
|
||||
// - add handling of backspace, tab, return keys
|
||||
// - fix doc. of VT100() constructor
|
||||
// - change from GPL to LGPL
|
||||
// 2007-07-09 - initial release
|
||||
//
|
||||
// class VT100
|
||||
// A_NORMAL, A_UNDERLINE, A_REVERSE, A_BLINK, A_DIM, A_BOLD, A_STANDOUT
|
||||
// =class constants=
|
||||
// Attribute constants.
|
||||
// VT100(wd, ht, scr_id) =constructor=
|
||||
// Creates a virtual terminal with width `wd', and
|
||||
// height `ht'. The terminal will be displayed between
|
||||
// <pre>...</pre> tags which have element ID `scr_id'.
|
||||
// addch(ch [, attr])
|
||||
// Writes out the character `ch'. If `attr' is given,
|
||||
// it specifies the attributes for the character,
|
||||
// otherwise the current attributes are used.
|
||||
// addstr(stuff) Writes out the string `stuff' using the current
|
||||
// attributes.
|
||||
// attroff(mode) Turns off any current options given in mode.
|
||||
// attron(mode) Turns on any options given in mode.
|
||||
// attrset(mode) Sets the current options to mode.
|
||||
// bkgdset(attr) Sets the background attributes to attr.
|
||||
// clear() Clears the terminal using the background attributes,
|
||||
// and homes the cursor.
|
||||
// clrtobol() Clears the portion of the terminal from the cursor
|
||||
// to the bottom.
|
||||
// clrtoeol() Clears the portion of the current line after the
|
||||
// cursor.
|
||||
// curs_set(vis [, grab])
|
||||
// If `vis' is 0, makes the cursor invisible; otherwise
|
||||
// make it visible. If `grab' is given and true, starts
|
||||
// capturing keyboard events (for `getch()'); if given
|
||||
// and false, stops capturing events.
|
||||
// echo() Causes key strokes to be automatically echoed on the
|
||||
// terminal.
|
||||
// erase() Same as `clear()'.
|
||||
// getch(isr) Arranges to call `isr' when a key stroke is
|
||||
// received. The received character and the terminal
|
||||
// object are passed as arguments to `isr'.
|
||||
// getmaxyx() Returns an associative array with the maximum row
|
||||
// (`y') and column (`x') numbers for the terminal.
|
||||
// getyx() Returns an associative array with the current row
|
||||
// (`y') and column (`x') of the cursor.
|
||||
// move(r, c) Moves the cursor to row `r', column `c'.
|
||||
// noecho() Stops automatically echoing key strokes.
|
||||
// refresh() Updates the display.
|
||||
// scroll() Scrolls the terminal up one line.
|
||||
// standend() Same as `attrset(VT100.A_NORMAL)'.
|
||||
// standout() Same as `attron(VT100.A_STANDOUT)'.
|
||||
// write(stuff) Writes `stuff' to the terminal and immediately
|
||||
// updates the display; (some) escape sequences are
|
||||
// interpreted and acted on.
|
||||
|
||||
// constructor
|
||||
function VT100(wd, ht, scr_id)
|
||||
{
|
||||
var r;
|
||||
var c;
|
||||
var scr = document.getElementById(scr_id);
|
||||
this.wd_ = wd;
|
||||
this.ht_ = ht;
|
||||
this.scrolled_ = 0;
|
||||
this.bkgd_ = {
|
||||
mode: VT100.A_NORMAL,
|
||||
fg: VT100.COLOR_WHITE,
|
||||
bg: VT100.COLOR_BLACK
|
||||
};
|
||||
this.c_attr_ = {
|
||||
mode: VT100.A_NORMAL,
|
||||
fg: VT100.COLOR_WHITE,
|
||||
bg: VT100.COLOR_BLACK
|
||||
};
|
||||
this.text_ = new Array(ht);
|
||||
this.attr_ = new Array(ht);
|
||||
for (r = 0; r < ht; ++r) {
|
||||
this.text_[r] = new Array(wd);
|
||||
this.attr_[r] = new Array(wd);
|
||||
}
|
||||
this.scr_ = scr;
|
||||
this.cursor_vis_ = true;
|
||||
this.grab_events_ = false;
|
||||
this.getch_isr_ = undefined;
|
||||
this.key_buf_ = [];
|
||||
this.echo_ = true;
|
||||
this.esc_state_ = 0;
|
||||
// Internal debug setting.
|
||||
this.debug_ = 0;
|
||||
this.clear();
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
// public constants -- colours and colour pairs
|
||||
VT100.COLOR_BLACK = 0;
|
||||
VT100.COLOR_BLUE = 1;
|
||||
VT100.COLOR_GREEN = 2;
|
||||
VT100.COLOR_CYAN = 3;
|
||||
VT100.COLOR_RED = 4;
|
||||
VT100.COLOR_MAGENTA = 5;
|
||||
VT100.COLOR_YELLOW = 6;
|
||||
VT100.COLOR_WHITE = 7;
|
||||
VT100.COLOR_PAIRS = 256;
|
||||
VT100.COLORS = 8;
|
||||
// public constants -- attributes
|
||||
VT100.A_NORMAL = 0;
|
||||
VT100.A_UNDERLINE = 1;
|
||||
VT100.A_REVERSE = 2;
|
||||
VT100.A_BLINK = 4;
|
||||
VT100.A_DIM = 8;
|
||||
VT100.A_BOLD = 16;
|
||||
VT100.A_STANDOUT = 32;
|
||||
VT100.A_PROTECT = VT100.A_INVIS = 0; // ?
|
||||
// other public constants
|
||||
VT100.TABSIZE = 8;
|
||||
// private constants
|
||||
VT100.ATTR_FLAGS_ = VT100.A_UNDERLINE | VT100.A_REVERSE | VT100.A_BLINK |
|
||||
VT100.A_DIM | VT100.A_BOLD | VT100.A_STANDOUT |
|
||||
VT100.A_PROTECT | VT100.A_INVIS;
|
||||
VT100.COLOR_SHIFT_ = 6;
|
||||
VT100.browser_ie_ = (navigator.appName.indexOf("Microsoft") != -1);
|
||||
VT100.browser_opera_ = (navigator.appName.indexOf("Opera") != -1);
|
||||
// class variables
|
||||
VT100.the_vt_ = undefined;
|
||||
|
||||
// class methods
|
||||
|
||||
// this is actually an event handler
|
||||
VT100.handle_onkeypress_ = function VT100_handle_onkeypress(event)
|
||||
{
|
||||
var vt = VT100.the_vt_, ch;
|
||||
if (vt === undefined)
|
||||
return true;
|
||||
if (VT100.browser_ie_ || VT100.browser_opera_) {
|
||||
ch = event.keyCode;
|
||||
if (ch == 13)
|
||||
ch = 10;
|
||||
else if (ch > 255 || (ch < 32 && ch != 8))
|
||||
return true;
|
||||
ch = String.fromCharCode(ch);
|
||||
} else {
|
||||
ch = event.charCode;
|
||||
//dump("ch: " + ch + "\n");
|
||||
//dump("ctrl?: " + event.ctrlKey + "\n");
|
||||
vt.debug("onkeypress:: keyCode: " + event.keyCode + ", ch: " + event.charCode);
|
||||
if (ch) {
|
||||
if (ch > 255)
|
||||
return true;
|
||||
if (event.ctrlKey && event.shiftKey) {
|
||||
// Don't send the copy/paste commands.
|
||||
var charStr = String.fromCharCode(ch);
|
||||
if (charStr == 'C' || charStr == 'V') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (event.ctrlKey) {
|
||||
ch = String.fromCharCode(ch - 96);
|
||||
} else {
|
||||
ch = String.fromCharCode(ch);
|
||||
if (ch == '\r')
|
||||
ch = '\n';
|
||||
}
|
||||
} else {
|
||||
switch (event.keyCode) {
|
||||
case event.DOM_VK_BACK_SPACE:
|
||||
ch = '\b';
|
||||
break;
|
||||
case event.DOM_VK_TAB:
|
||||
ch = '\t';
|
||||
// Stop tab from moving to another element.
|
||||
event.preventDefault();
|
||||
break;
|
||||
case event.DOM_VK_RETURN:
|
||||
case event.DOM_VK_ENTER:
|
||||
ch = '\n';
|
||||
break;
|
||||
case event.DOM_VK_UP:
|
||||
ch = '\x1b[A';
|
||||
break;
|
||||
case event.DOM_VK_DOWN:
|
||||
ch = '\x1b[B';
|
||||
break;
|
||||
case event.DOM_VK_RIGHT:
|
||||
ch = '\x1b[C';
|
||||
break;
|
||||
case event.DOM_VK_LEFT:
|
||||
ch = '\x1b[D';
|
||||
break;
|
||||
case event.DOM_VK_DELETE:
|
||||
ch = '\x1b[3~';
|
||||
break;
|
||||
case event.DOM_VK_HOME:
|
||||
ch = '\x1b[H';
|
||||
break;
|
||||
case event.DOM_VK_ESCAPE:
|
||||
ch = '\x1bc';
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
vt.key_buf_.push(ch);
|
||||
setTimeout(VT100.go_getch_, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// this is actually an event handler
|
||||
VT100.handle_onkeydown_ = function VT100_handle_onkeydown()
|
||||
{
|
||||
var vt = VT100.the_vt_, ch;
|
||||
switch (event.keyCode) {
|
||||
case 8:
|
||||
ch = '\b'; break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
vt.key_buf_.push(ch);
|
||||
setTimeout(VT100.go_getch_, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
VT100.go_getch_ = function VT100_go_getch()
|
||||
{
|
||||
var vt = VT100.the_vt_;
|
||||
if (vt === undefined)
|
||||
return;
|
||||
var isr = vt.getch_isr_;
|
||||
vt.getch_isr_ = undefined;
|
||||
if (isr === undefined)
|
||||
return;
|
||||
var ch = vt.key_buf_.shift();
|
||||
if (ch === undefined) {
|
||||
vt.getch_isr_ = isr;
|
||||
return;
|
||||
}
|
||||
if (vt.echo_)
|
||||
vt.addch(ch);
|
||||
isr(ch, vt);
|
||||
}
|
||||
|
||||
// object methods
|
||||
|
||||
VT100.prototype.may_scroll_ = function()
|
||||
{
|
||||
var ht = this.ht_, cr = this.row_;
|
||||
while (cr >= ht) {
|
||||
this.scroll();
|
||||
--cr;
|
||||
}
|
||||
this.row_ = cr;
|
||||
}
|
||||
|
||||
VT100.prototype.html_colours_ = function(attr)
|
||||
{
|
||||
var fg, bg, co0, co1;
|
||||
fg = attr.fg;
|
||||
bg = attr.bg;
|
||||
switch (attr.mode & (VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD)) {
|
||||
case 0:
|
||||
case VT100.A_DIM | VT100.A_BOLD:
|
||||
co0 = '00'; co1 = 'c0';
|
||||
break;
|
||||
case VT100.A_BOLD:
|
||||
co0 = '00'; co1 = 'ff';
|
||||
break;
|
||||
case VT100.A_DIM:
|
||||
if (fg == VT100.COLOR_BLACK)
|
||||
co0 = '40';
|
||||
else
|
||||
co0 = '00';
|
||||
co1 = '40';
|
||||
break;
|
||||
case VT100.A_REVERSE:
|
||||
case VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD:
|
||||
co0 = 'c0'; co1 = '40';
|
||||
break;
|
||||
case VT100.A_REVERSE | VT100.A_BOLD:
|
||||
co0 = 'c0'; co1 = '00';
|
||||
break;
|
||||
default:
|
||||
if (fg == VT100.COLOR_BLACK)
|
||||
co0 = '80';
|
||||
else
|
||||
co0 = 'c0';
|
||||
co1 = 'c0';
|
||||
}
|
||||
return {
|
||||
f: '#' + (fg & 4 ? co1 : co0) +
|
||||
(fg & 2 ? co1 : co0) +
|
||||
(fg & 1 ? co1 : co0),
|
||||
b: '#' + (bg & 4 ? co1 : co0) +
|
||||
(bg & 2 ? co1 : co0) +
|
||||
(bg & 1 ? co1 : co0)
|
||||
};
|
||||
}
|
||||
|
||||
VT100.prototype.addch = function(ch, attr)
|
||||
{
|
||||
var cc = this.col_;
|
||||
this.debug("addch:: ch: " + ch + ", attr: " + attr);
|
||||
switch (ch) {
|
||||
case '\b':
|
||||
if (cc != 0)
|
||||
--cc;
|
||||
break;
|
||||
case '\n':
|
||||
++this.row_;
|
||||
cc = 0;
|
||||
this.clrtoeol();
|
||||
this.may_scroll_();
|
||||
break;
|
||||
case '\r':
|
||||
this.may_scroll_();
|
||||
cc = 0;
|
||||
break;
|
||||
case '\t':
|
||||
this.may_scroll_();
|
||||
cc += VT100.TABSIZE - cc % VT100.TABSIZE;
|
||||
if (cc >= this.wd_) {
|
||||
++this.row_;
|
||||
cc -= this.wd_;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (attr === undefined)
|
||||
attr = this._cloneAttr(this.c_attr_);
|
||||
if (cc >= this.wd_) {
|
||||
++this.row_;
|
||||
cc = 0;
|
||||
}
|
||||
this.may_scroll_();
|
||||
this.text_[this.row_][cc] = ch;
|
||||
this.attr_[this.row_][cc] = attr;
|
||||
++cc;
|
||||
}
|
||||
this.col_ = cc;
|
||||
}
|
||||
|
||||
VT100.prototype.addstr = function(stuff)
|
||||
{
|
||||
for (var i = 0; i < stuff.length; ++i)
|
||||
this.addch(stuff.charAt(i));
|
||||
}
|
||||
|
||||
VT100.prototype._cloneAttr = function VT100_cloneAttr(a)
|
||||
{
|
||||
return {
|
||||
mode: a.mode,
|
||||
fg: a.fg,
|
||||
bg: a.bg
|
||||
};
|
||||
}
|
||||
|
||||
VT100.prototype.attroff = function(a)
|
||||
{
|
||||
//dump("attroff: " + a + "\n");
|
||||
a &= VT100.ATTR_FLAGS_;
|
||||
this.c_attr_.mode &= ~a;
|
||||
}
|
||||
|
||||
VT100.prototype.attron = function(a)
|
||||
{
|
||||
//dump("attron: " + a + "\n");
|
||||
a &= VT100.ATTR_FLAGS_;
|
||||
this.c_attr_.mode |= a;
|
||||
}
|
||||
|
||||
VT100.prototype.attrset = function(a)
|
||||
{
|
||||
//dump("attrset: " + a + "\n");
|
||||
this.c_attr_.mode = a;
|
||||
}
|
||||
|
||||
VT100.prototype.fgset = function(fg)
|
||||
{
|
||||
//dump("fgset: " + fg + "\n");
|
||||
this.c_attr_.fg = fg;
|
||||
}
|
||||
|
||||
VT100.prototype.bgset = function(bg)
|
||||
{
|
||||
//dump("bgset: " + bg + "\n");
|
||||
if (bg !== 0) {
|
||||
this.warn("bgset: " + bg + "\n");
|
||||
}
|
||||
this.c_attr_.bg = bg;
|
||||
}
|
||||
|
||||
VT100.prototype.bkgdset = function(a)
|
||||
{
|
||||
this.bkgd_ = a;
|
||||
}
|
||||
|
||||
VT100.prototype.clear = function()
|
||||
{
|
||||
this.debug("clear");
|
||||
this.row_ = this.col_ = 0;
|
||||
this.scrolled_ = 0;
|
||||
for (r = 0; r < this.ht_; ++r) {
|
||||
for (c = 0; c < this.wd_; ++c) {
|
||||
this.text_[r][c] = ' ';
|
||||
this.attr_[r][c] = this._cloneAttr(this.bkgd_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VT100.prototype.clrtobot = function()
|
||||
{
|
||||
this.debug("clrtobot, row: " + this.row_);
|
||||
var ht = this.ht_;
|
||||
var wd = this.wd_;
|
||||
this.clrtoeol();
|
||||
for (var r = this.row_ + 1; r < ht; ++r) {
|
||||
for (var c = 0; c < wd; ++c) {
|
||||
this.text_[r][c] = ' ';
|
||||
this.attr_[r][c] = this.bkgd_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VT100.prototype.clrtoeol = function()
|
||||
{
|
||||
this.debug("clrtoeol, col: " + this.col_);
|
||||
var r = this.row_;
|
||||
if (r >= this.ht_)
|
||||
return;
|
||||
for (var c = this.col_; c < this.wd_; ++c) {
|
||||
this.text_[r][c] = ' ';
|
||||
this.attr_[r][c] = this.bkgd_;
|
||||
}
|
||||
}
|
||||
|
||||
VT100.prototype.clearpos = function(row, col)
|
||||
{
|
||||
this.debug("clearpos (" + row + ", " + col + ")");
|
||||
if (row < 0 || row >= this.ht_)
|
||||
return;
|
||||
if (col < 0 || col >= this.wd_)
|
||||
return;
|
||||
this.text_[row][col] = ' ';
|
||||
this.attr_[row][col] = this.bkgd_;
|
||||
}
|
||||
|
||||
VT100.prototype.curs_set = function(vis, grab, eventist)
|
||||
{
|
||||
this.debug("curs_set:: vis: " + vis + ", grab: " + grab);
|
||||
if (vis !== undefined)
|
||||
this.cursor_vis_ = (vis > 0);
|
||||
if (eventist === undefined)
|
||||
eventist = window;
|
||||
if (grab === true || grab === false) {
|
||||
if (grab === this.grab_events_)
|
||||
return;
|
||||
if (grab) {
|
||||
this.grab_events_ = true;
|
||||
VT100.the_vt_ = this;
|
||||
eventist.addEventListener("keypress", VT100.handle_onkeypress_, false);
|
||||
if (VT100.browser_ie_)
|
||||
document.onkeydown = VT100.handle_onkeydown_;
|
||||
} else {
|
||||
eventist.removeEventListener("keypress", VT100.handle_onkeypress_, false);
|
||||
if (VT100.browser_ie_)
|
||||
document.onkeydown = VT100.handle_onkeydown_;
|
||||
this.grab_events_ = false;
|
||||
VT100.the_vt_ = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VT100.prototype.echo = function()
|
||||
{
|
||||
this.debug("echo on");
|
||||
this.echo_ = true;
|
||||
}
|
||||
|
||||
VT100.prototype.erase = VT100.prototype.clear;
|
||||
|
||||
VT100.prototype.getch = function(isr)
|
||||
{
|
||||
this.debug("getch");
|
||||
this.refresh();
|
||||
this.getch_isr_ = isr;
|
||||
setTimeout(VT100.go_getch_, 0);
|
||||
}
|
||||
|
||||
VT100.prototype.getmaxyx = function()
|
||||
{
|
||||
return { y: this.ht_ - 1, x: this.wd_ - 1 };
|
||||
}
|
||||
|
||||
VT100.prototype.getyx = function()
|
||||
{
|
||||
return { y: this.row_, x: this.col_ };
|
||||
}
|
||||
|
||||
VT100.prototype.move = function(r, c)
|
||||
{
|
||||
this.debug("move: (" + r + ", " + c + ")");
|
||||
if (r < 0)
|
||||
r = 0;
|
||||
else if (r >= this.ht_)
|
||||
r = this.ht_ - 1;
|
||||
if (c < 0)
|
||||
c = 0;
|
||||
else if (c >= this.wd_)
|
||||
c = this.wd_ - 1;
|
||||
this.row_ = r;
|
||||
this.col_ = c;
|
||||
}
|
||||
|
||||
VT100.prototype.noecho = function()
|
||||
{
|
||||
this.debug("echo off");
|
||||
this.echo_ = false;
|
||||
}
|
||||
|
||||
VT100.prototype.refresh = function()
|
||||
{
|
||||
this.debug("refresh");
|
||||
var r, c, stuff = "", start_tag = "", end_tag = "", at = -1, n_at, ch,
|
||||
pair, cr, cc, ht, wd, cv, added_end_tag;
|
||||
ht = this.ht_;
|
||||
wd = this.wd_;
|
||||
cr = this.row_;
|
||||
cc = this.col_;
|
||||
cv = this.cursor_vis_;
|
||||
var innerHTML = this.scr_.innerHTML;
|
||||
if (cc >= wd)
|
||||
cc = wd - 1;
|
||||
for (r = 0; r < ht; ++r) {
|
||||
if (r > 0) {
|
||||
stuff += '\n';
|
||||
}
|
||||
for (c = 0; c < wd; ++c) {
|
||||
added_end_tag = false;
|
||||
n_at = this.attr_[r][c];
|
||||
if (cv && r == cr && c == cc) {
|
||||
// Draw the cursor here.
|
||||
n_at = this._cloneAttr(n_at);
|
||||
n_at.mode ^= VT100.A_REVERSE;
|
||||
}
|
||||
// If the attributes changed, make a new span.
|
||||
if (n_at.mode != at.mode || n_at.fg != at.fg || n_at.bg != at.bg) {
|
||||
if (c > 0) {
|
||||
stuff += end_tag;
|
||||
}
|
||||
start_tag = "";
|
||||
end_tag = "";
|
||||
if (n_at.mode & VT100.A_BLINK) {
|
||||
start_tag = "<blink>";
|
||||
end_tag = "</blink>" + end_tag;
|
||||
}
|
||||
if (n_at.mode & VT100.A_STANDOUT)
|
||||
n_at.mode |= VT100.A_BOLD;
|
||||
pair = this.html_colours_(n_at);
|
||||
start_tag += '<span style="color:' + pair.f +
|
||||
';background-color:' + pair.b;
|
||||
if (n_at.mode & VT100.A_UNDERLINE)
|
||||
start_tag += ';text-decoration:underline';
|
||||
start_tag += ';">';
|
||||
stuff += start_tag;
|
||||
end_tag = "</span>" + end_tag;
|
||||
at = n_at;
|
||||
added_end_tag = true;
|
||||
} else if (c == 0) {
|
||||
stuff += start_tag;
|
||||
}
|
||||
ch = this.text_[r][c];
|
||||
switch (ch) {
|
||||
case '&':
|
||||
stuff += '&'; break;
|
||||
case '<':
|
||||
stuff += '<'; break;
|
||||
case '>':
|
||||
stuff += '>'; break;
|
||||
case ' ':
|
||||
//stuff += ' '; break;
|
||||
stuff += ' '; break;
|
||||
default:
|
||||
stuff += ch;
|
||||
}
|
||||
}
|
||||
if (!added_end_tag)
|
||||
stuff += end_tag;
|
||||
}
|
||||
this.scr_.innerHTML = "<b>" + stuff + "</b>\n";
|
||||
}
|
||||
|
||||
VT100.prototype.scroll = function()
|
||||
{
|
||||
this.scrolled_ += 1;
|
||||
this.debug("scrolled: " + this.scrolled_);
|
||||
var n_text = this.text_[0], n_attr = this.attr_[0],
|
||||
ht = this.ht_, wd = this.wd_;
|
||||
for (var r = 1; r < ht; ++r) {
|
||||
this.text_[r - 1] = this.text_[r];
|
||||
this.attr_[r - 1] = this.attr_[r];
|
||||
}
|
||||
this.text_[ht - 1] = n_text;
|
||||
this.attr_[ht - 1] = n_attr;
|
||||
for (var c = 0; c < wd; ++c) {
|
||||
n_text[c] = ' ';
|
||||
n_attr[c] = this.bkgd_;
|
||||
}
|
||||
}
|
||||
|
||||
VT100.prototype.standend = function()
|
||||
{
|
||||
//this.debug("standend");
|
||||
this.attrset(0);
|
||||
}
|
||||
|
||||
VT100.prototype.standout = function()
|
||||
{
|
||||
//this.debug("standout");
|
||||
this.attron(VT100.A_STANDOUT);
|
||||
}
|
||||
|
||||
VT100.prototype.write = function(stuff)
|
||||
{
|
||||
var ch, x, r, c, i, j, yx, myx;
|
||||
for (i = 0; i < stuff.length; ++i) {
|
||||
ch = stuff.charAt(i);
|
||||
if (ch == '\x0D') {
|
||||
this.debug("write:: ch: " + ch.charCodeAt(0) + ", '\\x0D'");
|
||||
} else {
|
||||
this.debug("write:: ch: " + ch.charCodeAt(0) + ", '" + (ch == '\x1b' ? "ESC" : ch) + "'");
|
||||
}
|
||||
//dump("ch: " + ch.charCodeAt(0) + ", '" + (ch == '\x1b' ? "ESC" : ch) + "'\n");
|
||||
switch (ch) {
|
||||
case '\x00':
|
||||
case '\x7f':
|
||||
case '\x07': /* bell, ignore it */
|
||||
this.debug("write:: ignoring bell character: " + ch);
|
||||
continue;
|
||||
case '\a':
|
||||
case '\b':
|
||||
case '\t':
|
||||
case '\r':
|
||||
this.addch(ch);
|
||||
continue;
|
||||
case '\n':
|
||||
case '\v':
|
||||
case '\f': // what a mess
|
||||
yx = this.getyx();
|
||||
myx = this.getmaxyx();
|
||||
if (yx.y >= myx.y) {
|
||||
this.scroll();
|
||||
this.move(myx.y, 0);
|
||||
} else
|
||||
this.move(yx.y + 1, 0);
|
||||
continue;
|
||||
case '\x18':
|
||||
case '\x1a':
|
||||
this.esc_state_ = 0;
|
||||
this.debug("write:: set escape state: 0");
|
||||
continue;
|
||||
case '\x1b':
|
||||
this.esc_state_ = 1;
|
||||
this.debug("write:: set escape state: 1");
|
||||
continue;
|
||||
case '\x9b':
|
||||
this.esc_state_ = 2;
|
||||
this.debug("write:: set escape state: 2");
|
||||
continue;
|
||||
}
|
||||
// not a recognized control character
|
||||
switch (this.esc_state_) {
|
||||
case 0: // not in escape sequence
|
||||
this.addch(ch);
|
||||
break;
|
||||
case 1: // just saw ESC
|
||||
switch (ch) {
|
||||
case '[':
|
||||
this.esc_state_ = 2;
|
||||
this.debug("write:: set escape state: 2");
|
||||
break;
|
||||
case '=':
|
||||
/* Set keypade mode (ignored) */
|
||||
this.debug("write:: set keypade mode: ignored");
|
||||
this.esc_state_ = 0;
|
||||
break;
|
||||
case '>':
|
||||
/* Reset keypade mode (ignored) */
|
||||
this.debug("write:: reset keypade mode: ignored");
|
||||
this.esc_state_ = 0;
|
||||
break;
|
||||
case 'H':
|
||||
/* Set tab at cursor column (ignored) */
|
||||
this.debug("write:: set tab cursor column: ignored");
|
||||
this.esc_state_ = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2: // just saw CSI
|
||||
switch (ch) {
|
||||
case 'K':
|
||||
/* Erase in Line */
|
||||
this.esc_state_ = 0;
|
||||
this.clrtoeol();
|
||||
continue;
|
||||
case 'H':
|
||||
/* Move to (0,0). */
|
||||
this.esc_state_ = 0;
|
||||
this.move(0, 0);
|
||||
continue;
|
||||
case 'J':
|
||||
/* Clear to the bottom. */
|
||||
this.esc_state_ = 0;
|
||||
this.clrtobot();
|
||||
continue;
|
||||
case '?':
|
||||
/* Special VT100 mode handling. */
|
||||
this.esc_state_ = 5;
|
||||
this.debug("write:: special vt100 mode");
|
||||
continue;
|
||||
}
|
||||
// Drop through to next case.
|
||||
this.csi_parms_ = [0];
|
||||
this.debug("write:: set escape state: 3");
|
||||
this.esc_state_ = 3;
|
||||
case 3: // saw CSI and parameters
|
||||
switch (ch) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
x = this.csi_parms_.pop();
|
||||
this.csi_parms_.push(x * 10 + ch * 1);
|
||||
this.debug("csi_parms_: " + this.csi_parms_);
|
||||
continue;
|
||||
case ';':
|
||||
if (this.csi_parms_.length < 17)
|
||||
this.csi_parms_.push(0);
|
||||
continue;
|
||||
}
|
||||
this.esc_state_ = 0;
|
||||
switch (ch) {
|
||||
case 'A':
|
||||
// Cursor Up <ESC>[{COUNT}A
|
||||
this.move(this.row_ - Math.max(1, this.csi_parms_[0]),
|
||||
this.col_);
|
||||
break;
|
||||
case 'B':
|
||||
// Cursor Down <ESC>[{COUNT}B
|
||||
this.move(this.row_ + Math.max(1, this.csi_parms_[0]),
|
||||
this.col_);
|
||||
break;
|
||||
case 'C':
|
||||
// Cursor Forward <ESC>[{COUNT}C
|
||||
this.move(this.row_,
|
||||
this.col_ + Math.max(1, this.csi_parms_[0]));
|
||||
break;
|
||||
case 'c':
|
||||
this.warn("write:: got TERM query");
|
||||
break;
|
||||
case 'D':
|
||||
// Cursor Backward <ESC>[{COUNT}D
|
||||
this.move(this.row_,
|
||||
this.col_ - Math.max(1, this.csi_parms_[0]));
|
||||
break;
|
||||
case 'f':
|
||||
case 'H':
|
||||
// Cursor Home <ESC>[{ROW};{COLUMN}H
|
||||
this.csi_parms_.push(0);
|
||||
this.move(this.csi_parms_[0] - 1,
|
||||
this.csi_parms_[1] - 1);
|
||||
break;
|
||||
case 'J':
|
||||
switch (this.csi_parms_[0]) {
|
||||
case 0:
|
||||
this.clrtobot();
|
||||
break;
|
||||
case 2:
|
||||
this.clear();
|
||||
this.move(0, 0);
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
for (j=0; j<this.csi_parms_.length; ++j) {
|
||||
x = this.csi_parms_[j];
|
||||
switch (x) {
|
||||
case 0:
|
||||
this.standend();
|
||||
this.fgset(this.bkgd_.fg);
|
||||
this.bgset(this.bkgd_.bg);
|
||||
break;
|
||||
case 1:
|
||||
this.attron(VT100.A_BOLD);
|
||||
break;
|
||||
case 30:
|
||||
this.fgset(VT100.COLOR_BLACK);
|
||||
break;
|
||||
case 31:
|
||||
this.fgset(VT100.COLOR_RED);
|
||||
break;
|
||||
case 32:
|
||||
this.fgset(VT100.COLOR_GREEN);
|
||||
break;
|
||||
case 33:
|
||||
this.fgset(VT100.COLOR_YELLOW);
|
||||
break;
|
||||
case 34:
|
||||
this.fgset(VT100.COLOR_BLUE);
|
||||
break;
|
||||
case 35:
|
||||
this.fgset(VT100.COLOR_MAGENTA);
|
||||
break;
|
||||
case 36:
|
||||
this.fgset(VT100.COLOR_CYAN);
|
||||
break;
|
||||
case 37:
|
||||
this.fgset(VT100.COLOR_WHITE);
|
||||
break;
|
||||
case 40:
|
||||
this.bgset(VT100.COLOR_BLACK);
|
||||
break;
|
||||
case 41:
|
||||
this.bgset(VT100.COLOR_RED);
|
||||
break;
|
||||
case 42:
|
||||
this.bgset(VT100.COLOR_GREEN);
|
||||
break;
|
||||
case 44:
|
||||
this.bgset(VT100.COLOR_YELLOW);
|
||||
break;
|
||||
case 44:
|
||||
this.bgset(VT100.COLOR_BLUE);
|
||||
break;
|
||||
case 45:
|
||||
this.bgset(VT100.COLOR_MAGENTA);
|
||||
break;
|
||||
case 46:
|
||||
this.bgset(VT100.COLOR_CYAN);
|
||||
break;
|
||||
case 47:
|
||||
this.bgset(VT100.COLOR_WHITE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
// 1,24r - set scrolling region (ignored)
|
||||
break;
|
||||
case '[':
|
||||
this.debug("write:: set escape state: 4");
|
||||
this.esc_state_ = 4;
|
||||
break;
|
||||
case 'g':
|
||||
// 0g: clear tab at cursor (ignored)
|
||||
// 3g: clear all tabs (ignored)
|
||||
break;
|
||||
default:
|
||||
this.warn("write:: unknown command: " + ch);
|
||||
this.csi_parms_ = [];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4: // saw CSI [
|
||||
this.esc_state_ = 0; // gobble char.
|
||||
break;
|
||||
case 5: // Special mode handling, saw <ESC>[?
|
||||
// Expect a number - the reset type
|
||||
this.csi_parms_ = [ch];
|
||||
this.esc_state_ = 6;
|
||||
break;
|
||||
case 6: // Reset mode handling, saw <ESC>[?1
|
||||
// Expect a letter - the mode target, example:
|
||||
// <ESC>[?1l : cursor key mode = cursor
|
||||
// <ESC>[?1h : save current screen, create new empty
|
||||
// screen and position at 0,0
|
||||
// <ESC>[?5l : White on blk
|
||||
// XXX: Ignored for now.
|
||||
//dump("Saw reset mode: <ESC>[?" + this.csi_parms_[0] + ch + "\n");
|
||||
this.esc_state_ = 0;
|
||||
this.debug("write:: set escape state: 0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
VT100.prototype.debug = function(message) {
|
||||
if (this.debug_) {
|
||||
dump(message + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
VT100.prototype.warn = function(message) {
|
||||
dump(message + "\n");
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
This software is covered under the following copyright:
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* BigInteger, RSA, Random and ARC4 are derivative works of the jsbn library
|
||||
* (http://www-cs-students.stanford.edu/~tjw/jsbn/)
|
||||
* The jsbn library is Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU)
|
||||
*
|
||||
* MD5, SHA1, and SHA256 are derivative works (http://pajhome.org.uk/crypt/md5/)
|
||||
* Those are Copyright (c) 1998-2002 Paul Johnston & Contributors (paj@pajhome.org.uk)
|
||||
*
|
||||
* SHA256 is a derivative work of jsSHA2 (http://anmar.eu.org/projects/jssha2/)
|
||||
* jsSHA2 is Copyright (c) 2003-2004 Angel Marin (anmar@gmx.net)
|
||||
*
|
||||
* AESKey is a derivative work of aestable.c (http://www.geocities.com/malbrain/aestable_c.html)
|
||||
* aestable.c is Copyright (c) Karl Malbrain (malbrain@yahoo.com)
|
||||
*
|
||||
* BlowFishKey, DESKey and TripeDESKey are derivative works of the Bouncy Castle Crypto Package (http://www.bouncycastle.org)
|
||||
* Those are Copyright (c) 2000-2004 The Legion Of The Bouncy Castle
|
||||
*
|
||||
* Base64 is copyright (c) 2006 Steve Webster (http://dynamicflash.com/goodies/base64)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer. Redistributions in binary form must
|
||||
* reproduce the above copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the author nor the names of its contributors may be used to endorse
|
||||
* or promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
||||
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
|
||||
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
|
||||
* THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
Address all questions regarding this license to:
|
||||
|
||||
Henri Torgemane
|
||||
henri_torgemane@yahoo.com
|
||||
|
||||
|
||||
Additionally, the MD5 algorithm is covered by the following notice:
|
||||
|
||||
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
|
||||
*
|
||||
* License to copy and use this software is granted provided that it
|
||||
* is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
* Algorithm" in all material mentioning or referencing this software
|
||||
* or this function.
|
||||
*
|
||||
* License is also granted to make and use derivative works provided
|
||||
* that such works are identified as "derived from the RSA Data
|
||||
* Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
* mentioning or referencing the derived work.
|
||||
*
|
||||
* RSA Data Security, Inc. makes no representations concerning either
|
||||
* the merchantability of this software or the suitability of this
|
||||
* software for any particular purpose. It is provided "as is"
|
||||
* without express or implied warranty of any kind.
|
||||
*
|
||||
* These notices must be retained in any copies of any part of this
|
||||
* documentation and/or software.
|
||||
*/
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
= DESCRIPTION
|
||||
|
||||
as3crypto 1.3 has some bugs, at r28(latest version of original svn-repository),
|
||||
many of them are fixed, but there are another bugs around a new ASN1 parser.
|
||||
so I copied some features from r28 to 1.3
|
||||
version, and fixed them to be built without error.
|
||||
and added build-swc.xml
|
||||
|
||||
= LICENSE
|
||||
|
||||
See LICENCE.txt,
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
require 'rubygems'
|
||||
require 'airake'
|
||||
|
||||
ENV["AIRAKE_ROOT"] = File.dirname(__FILE__)
|
||||
ENV["AIRAKE_ENV"] = "development"
|
||||
|
||||
# Aliases
|
||||
task :test => [ "air:test" ] do; end
|
||||
task :compile => [ "air:compile" ] do; end
|
||||
task :package => [ "air:package" ] do; end
|
||||
task :certificate => [ "air:certificate" ] do; end
|
||||
task :adl => [ "air:adl" ] do; end
|
||||
task :docs => [ "air:docs" ] do; end
|
||||
task :clean => [ "air:clean" ] do; end
|
||||
task :acompc => [ "air:acompc" ] do; end
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
mxml_path: src/As3crypto.mxml
|
||||
appxml_path: src/As3crypto-app.xml
|
||||
|
||||
src_dirs: [ 'src' ]
|
||||
lib_dir: lib
|
||||
|
||||
air_path: bin/As3crypto.air
|
||||
swf_path: bin/As3crypto.swf
|
||||
assets: src/assets
|
||||
certificate: cert.pfx
|
||||
|
||||
development:
|
||||
debug: true
|
||||
|
||||
test:
|
||||
swf_path: bin/Test.swf
|
||||
mxml_path: test/Test.mxml
|
||||
appxml_path: test/Test-app.xml
|
||||
src_dirs: [ 'src', 'test' ]
|
||||
debug: true
|
||||
Binary file not shown.
@@ -0,0 +1,109 @@
|
||||
<!--
|
||||
To build as3crypto.swc, use
|
||||
|
||||
compc -load-config=build-swc.xml
|
||||
|
||||
If you need Flash Player 9 support, change the path below to something more
|
||||
appropriate for your SDK and/or Player version
|
||||
-->
|
||||
<flex-config>
|
||||
<benchmark>true</benchmark>
|
||||
<compiler>
|
||||
<external-library-path>
|
||||
<path-element>${flexlib}/libs/player/10.0/playerglobal.swc</path-element>
|
||||
</external-library-path>
|
||||
<source-path>
|
||||
<path-element>./src</path-element>
|
||||
</source-path>
|
||||
</compiler>
|
||||
<include-classes>
|
||||
<class>com.hurlant.crypto.Crypto</class>
|
||||
<class>com.hurlant.crypto.cert.MozillaRootCertificates</class>
|
||||
<class>com.hurlant.crypto.cert.X509Certificate</class>
|
||||
<class>com.hurlant.crypto.cert.X509CertificateCollection</class>
|
||||
<class>com.hurlant.crypto.hash.HMAC</class>
|
||||
<class>com.hurlant.crypto.hash.IHMAC</class>
|
||||
<class>com.hurlant.crypto.hash.IHash</class>
|
||||
<class>com.hurlant.crypto.hash.MAC</class>
|
||||
<class>com.hurlant.crypto.hash.MD2</class>
|
||||
<class>com.hurlant.crypto.hash.MD5</class>
|
||||
<class>com.hurlant.crypto.hash.SHA1</class>
|
||||
<class>com.hurlant.crypto.hash.SHA224</class>
|
||||
<class>com.hurlant.crypto.hash.SHA256</class>
|
||||
<class>com.hurlant.crypto.hash.SHABase</class>
|
||||
<class>com.hurlant.crypto.prng.ARC4</class>
|
||||
<class>com.hurlant.crypto.prng.IPRNG</class>
|
||||
<class>com.hurlant.crypto.prng.Random</class>
|
||||
<class>com.hurlant.crypto.prng.TLSPRF</class>
|
||||
<class>com.hurlant.crypto.rsa.RSAKey</class>
|
||||
<class>com.hurlant.crypto.symmetric.AESKey</class>
|
||||
<class>com.hurlant.crypto.symmetric.BlowFishKey</class>
|
||||
<class>com.hurlant.crypto.symmetric.CBCMode</class>
|
||||
<class>com.hurlant.crypto.symmetric.CFB8Mode</class>
|
||||
<class>com.hurlant.crypto.symmetric.CFBMode</class>
|
||||
<class>com.hurlant.crypto.symmetric.CTRMode</class>
|
||||
<class>com.hurlant.crypto.symmetric.DESKey</class>
|
||||
<class>com.hurlant.crypto.symmetric.ECBMode</class>
|
||||
<class>com.hurlant.crypto.symmetric.ICipher</class>
|
||||
<class>com.hurlant.crypto.symmetric.IMode</class>
|
||||
<class>com.hurlant.crypto.symmetric.IPad</class>
|
||||
<class>com.hurlant.crypto.symmetric.IStreamCipher</class>
|
||||
<class>com.hurlant.crypto.symmetric.ISymmetricKey</class>
|
||||
<class>com.hurlant.crypto.symmetric.IVMode</class>
|
||||
<class>com.hurlant.crypto.symmetric.NullPad</class>
|
||||
<class>com.hurlant.crypto.symmetric.OFBMode</class>
|
||||
<class>com.hurlant.crypto.symmetric.PKCS5</class>
|
||||
<class>com.hurlant.crypto.symmetric.SimpleIVMode</class>
|
||||
<class>com.hurlant.crypto.symmetric.TLSPad</class>
|
||||
<class>com.hurlant.crypto.symmetric.SSLPad</class>
|
||||
<class>com.hurlant.crypto.symmetric.TripleDESKey</class>
|
||||
<class>com.hurlant.crypto.symmetric.XTeaKey</class>
|
||||
<class>com.hurlant.crypto.tls.BulkCiphers</class>
|
||||
<class>com.hurlant.crypto.tls.CipherSuites</class>
|
||||
<class>com.hurlant.crypto.tls.KeyExchanges</class>
|
||||
<class>com.hurlant.crypto.tls.MACs</class>
|
||||
<class>com.hurlant.crypto.tls.TLSConfig</class>
|
||||
<class>com.hurlant.crypto.tls.IConnectionState</class>
|
||||
<class>com.hurlant.crypto.tls.TLSConnectionState</class>
|
||||
<class>com.hurlant.crypto.tls.SSLConnectionState</class>
|
||||
<class>com.hurlant.crypto.tls.TLSEngine</class>
|
||||
<class>com.hurlant.crypto.tls.TLSError</class>
|
||||
<class>com.hurlant.crypto.tls.TLSSocketEvent</class>
|
||||
<class>com.hurlant.crypto.tls.TLSEvent</class>
|
||||
<class>com.hurlant.crypto.tls.SSLEvent</class>
|
||||
<class>com.hurlant.crypto.tls.ISecurityParameters</class>
|
||||
<class>com.hurlant.crypto.tls.TLSSecurityParameters</class>
|
||||
<class>com.hurlant.crypto.tls.SSLSecurityParameters</class>
|
||||
<class>com.hurlant.crypto.tls.TLSSocket</class>
|
||||
<class>com.hurlant.util.ArrayUtil</class>
|
||||
<class>com.hurlant.util.Base64</class>
|
||||
<class>com.hurlant.util.Hex</class>
|
||||
<class>com.hurlant.util.Memory</class>
|
||||
<class>com.hurlant.util.der.ByteString</class>
|
||||
<class>com.hurlant.util.der.DER</class>
|
||||
<class>com.hurlant.util.der.IAsn1Type</class>
|
||||
<class>com.hurlant.util.der.Integer</class>
|
||||
<class>com.hurlant.util.der.OID</class>
|
||||
<class>com.hurlant.util.der.ObjectIdentifier</class>
|
||||
<class>com.hurlant.util.der.PEM</class>
|
||||
<class>com.hurlant.util.der.PrintableString</class>
|
||||
<class>com.hurlant.util.der.Sequence</class>
|
||||
<class>com.hurlant.util.der.Set</class>
|
||||
<class>com.hurlant.util.der.Type</class>
|
||||
<class>com.hurlant.util.der.UTCTime</class>
|
||||
<class>com.hurlant.math.BarrettReduction</class>
|
||||
<class>com.hurlant.math.BigInteger</class>
|
||||
<class>com.hurlant.math.ClassicReduction</class>
|
||||
<class>com.hurlant.math.IReduction</class>
|
||||
<class>com.hurlant.math.MontgomeryReduction</class>
|
||||
<class>com.hurlant.math.NullReduction</class>
|
||||
<class>com.hurlant.math.bi_internal</class>
|
||||
</include-classes>
|
||||
<metadata>
|
||||
<creator>Henri Torgemane</creator>
|
||||
<description>http://crypto.hurlant.com/</description>
|
||||
<language>EN</language>
|
||||
<title>AS3 Cryptography Library</title>
|
||||
</metadata>
|
||||
<output>bin/as3crypto_patched.swc</output>
|
||||
</flex-config>
|
||||
Binary file not shown.
Binary file not shown.
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env ruby
|
||||
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
||||
|
||||
begin
|
||||
require 'rubigen'
|
||||
rescue LoadError
|
||||
require 'rubygems'
|
||||
require 'rubigen'
|
||||
end
|
||||
require 'rubigen/scripts/destroy'
|
||||
|
||||
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
||||
RubiGen::Base.use_component_sources! [:air, :airake, :test_unit]
|
||||
RubiGen::Scripts::Destroy.new.run(ARGV)
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env ruby
|
||||
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
||||
|
||||
begin
|
||||
require 'rubigen'
|
||||
rescue LoadError
|
||||
require 'rubygems'
|
||||
require 'rubigen'
|
||||
end
|
||||
require 'rubigen/scripts/generate'
|
||||
|
||||
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
||||
RubiGen::Base.use_component_sources! [:air, :airake, :test_unit]
|
||||
RubiGen::Scripts::Generate.new.run(ARGV)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* Crypto
|
||||
*
|
||||
* An abstraction layer to instanciate our crypto algorithms
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto
|
||||
{
|
||||
import com.hurlant.crypto.hash.HMAC;
|
||||
import com.hurlant.crypto.hash.MAC;
|
||||
import com.hurlant.crypto.hash.IHash;
|
||||
import com.hurlant.crypto.hash.MD2;
|
||||
import com.hurlant.crypto.hash.MD5;
|
||||
import com.hurlant.crypto.hash.SHA1;
|
||||
import com.hurlant.crypto.hash.SHA224;
|
||||
import com.hurlant.crypto.hash.SHA256;
|
||||
import com.hurlant.crypto.prng.ARC4;
|
||||
import com.hurlant.crypto.rsa.RSAKey;
|
||||
import com.hurlant.crypto.symmetric.AESKey;
|
||||
import com.hurlant.crypto.symmetric.BlowFishKey;
|
||||
import com.hurlant.crypto.symmetric.CBCMode;
|
||||
import com.hurlant.crypto.symmetric.CFB8Mode;
|
||||
import com.hurlant.crypto.symmetric.CFBMode;
|
||||
import com.hurlant.crypto.symmetric.CTRMode;
|
||||
import com.hurlant.crypto.symmetric.DESKey;
|
||||
import com.hurlant.crypto.symmetric.ECBMode;
|
||||
import com.hurlant.crypto.symmetric.ICipher;
|
||||
import com.hurlant.crypto.symmetric.IMode;
|
||||
import com.hurlant.crypto.symmetric.IPad;
|
||||
import com.hurlant.crypto.symmetric.ISymmetricKey;
|
||||
import com.hurlant.crypto.symmetric.IVMode;
|
||||
import com.hurlant.crypto.symmetric.NullPad;
|
||||
import com.hurlant.crypto.symmetric.OFBMode;
|
||||
import com.hurlant.crypto.symmetric.PKCS5;
|
||||
import com.hurlant.crypto.symmetric.SimpleIVMode;
|
||||
import com.hurlant.crypto.symmetric.TripleDESKey;
|
||||
import com.hurlant.crypto.symmetric.XTeaKey;
|
||||
import com.hurlant.util.Base64;
|
||||
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
/**
|
||||
* A class to make it easy to use the rest of the framework.
|
||||
* As a side-effect, using this class will cause most of the framework
|
||||
* to be linked into your application, which is not always what you want.
|
||||
*
|
||||
* If you want to optimize your download size, don't use this class.
|
||||
* (But feel free to read it to get ideas on how to get the algorithm you want.)
|
||||
*/
|
||||
public class Crypto
|
||||
{
|
||||
private var b64:Base64; // we don't use it, but we want the swc to include it, so cheap trick.
|
||||
|
||||
public function Crypto(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Things that should work, among others:
|
||||
* "aes"
|
||||
* "aes-128-ecb"
|
||||
* "aes-128-cbc"
|
||||
* "aes-128-cfb"
|
||||
* "aes-128-cfb8"
|
||||
* "aes-128-ofb"
|
||||
* "aes-192-cfb"
|
||||
* "aes-256-ofb"
|
||||
* "blowfish-cbc"
|
||||
* "des-ecb"
|
||||
* "xtea"
|
||||
* "xtea-ecb"
|
||||
* "xtea-cbc"
|
||||
* "xtea-cfb"
|
||||
* "xtea-cfb8"
|
||||
* "xtea-ofb"
|
||||
* "rc4"
|
||||
* "simple-aes-cbc"
|
||||
*/
|
||||
public static function getCipher(name:String, key:ByteArray, pad:IPad=null):ICipher {
|
||||
// split name into an array.
|
||||
var keys:Array = name.split("-");
|
||||
switch (keys[0]) {
|
||||
/**
|
||||
* "simple" is a special case. It means:
|
||||
* "If using an IV mode, prepend the IV to the ciphertext"
|
||||
*/
|
||||
case "simple":
|
||||
keys.shift();
|
||||
name = keys.join("-");
|
||||
var cipher:ICipher = getCipher(name, key, pad);
|
||||
if (cipher is IVMode) {
|
||||
return new SimpleIVMode(cipher as IVMode);
|
||||
} else {
|
||||
return cipher;
|
||||
}
|
||||
/**
|
||||
* we support both "aes-128" and "aes128"
|
||||
* Technically, you could use "aes192-128", but you'd
|
||||
* only be hurting yourself.
|
||||
*/
|
||||
case "aes":
|
||||
case "aes128":
|
||||
case "aes192":
|
||||
case "aes256":
|
||||
keys.shift();
|
||||
if (key.length*8==keys[0]) {
|
||||
// support for "aes-128-..." and such.
|
||||
keys.shift();
|
||||
}
|
||||
return getMode(keys[0], new AESKey(key), pad);
|
||||
break;
|
||||
case "bf":
|
||||
case "blowfish":
|
||||
keys.shift();
|
||||
return getMode(keys[0], new BlowFishKey(key), pad);
|
||||
/**
|
||||
* des-ede and des-ede3 are both equivalent to des3.
|
||||
* the choice between 2tdes and 3tdes is made based
|
||||
* on the length of the key provided.
|
||||
*/
|
||||
case "des":
|
||||
keys.shift();
|
||||
if (keys[0]!="ede" && keys[0]!="ede3") {
|
||||
return getMode(keys[0], new DESKey(key), pad);
|
||||
}
|
||||
if (keys.length==1) {
|
||||
keys.push("ecb"); // default mode for 2tdes and 3tdes with openssl enc
|
||||
}
|
||||
// fall-through to triple des
|
||||
case "3des":
|
||||
case "des3":
|
||||
keys.shift();
|
||||
return getMode(keys[0], new TripleDESKey(key), pad);
|
||||
case "xtea":
|
||||
keys.shift();
|
||||
return getMode(keys[0], new XTeaKey(key), pad);
|
||||
break;
|
||||
/**
|
||||
* Technically, you could say "rc4-128" or whatever,
|
||||
* but really, the length of the key is what counts here.
|
||||
*/
|
||||
case "rc4":
|
||||
keys.shift();
|
||||
return new ARC4(key);
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of a key for a given cipher identifier.
|
||||
*/
|
||||
public static function getKeySize(name:String):uint {
|
||||
var keys:Array = name.split("-");
|
||||
switch (keys[0]) {
|
||||
case "simple":
|
||||
keys.shift();
|
||||
return getKeySize(keys.join("-"));
|
||||
case "aes128":
|
||||
return 16;
|
||||
case "aes192":
|
||||
return 24;
|
||||
case "aes256":
|
||||
return 32;
|
||||
case "aes":
|
||||
keys.shift();
|
||||
return parseInt(keys[0])/8;
|
||||
case "bf":
|
||||
case "blowfish":
|
||||
return 16;
|
||||
case "des":
|
||||
keys.shift();
|
||||
switch (keys[0]) {
|
||||
case "ede":
|
||||
return 16;
|
||||
case "ede3":
|
||||
return 24;
|
||||
default:
|
||||
return 8;
|
||||
}
|
||||
case "3des":
|
||||
case "des3":
|
||||
return 24;
|
||||
case "xtea":
|
||||
return 8;
|
||||
case "rc4":
|
||||
if (parseInt(keys[1])>0) {
|
||||
return parseInt(keys[1])/8;
|
||||
}
|
||||
return 16; // why not.
|
||||
}
|
||||
return 0; // unknown;
|
||||
}
|
||||
|
||||
private static function getMode(name:String, alg:ISymmetricKey, padding:IPad=null):IMode {
|
||||
switch (name) {
|
||||
case "ecb":
|
||||
return new ECBMode(alg, padding);
|
||||
case "cfb":
|
||||
return new CFBMode(alg, padding);
|
||||
case "cfb8":
|
||||
return new CFB8Mode(alg, padding);
|
||||
case "ofb":
|
||||
return new OFBMode(alg, padding);
|
||||
case "ctr":
|
||||
return new CTRMode(alg, padding);
|
||||
case "cbc":
|
||||
default:
|
||||
return new CBCMode(alg, padding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Things that should work:
|
||||
* "md5"
|
||||
* "sha"
|
||||
* "sha1"
|
||||
* "sha224"
|
||||
* "sha256"
|
||||
*/
|
||||
public static function getHash(name:String):IHash {
|
||||
switch(name) {
|
||||
case "md2":
|
||||
return new MD2;
|
||||
case "md5":
|
||||
return new MD5;
|
||||
case "sha": // let's hope you didn't mean sha-0
|
||||
case "sha1":
|
||||
return new SHA1;
|
||||
case "sha224":
|
||||
return new SHA224;
|
||||
case "sha256":
|
||||
return new SHA256;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Things that should work:
|
||||
* "sha1"
|
||||
* "md5-64"
|
||||
* "hmac-md5-96"
|
||||
* "hmac-sha1-128"
|
||||
* "hmac-sha256-192"
|
||||
* etc.
|
||||
*/
|
||||
public static function getHMAC(name:String):HMAC {
|
||||
var keys:Array = name.split("-");
|
||||
if (keys[0]=="hmac") keys.shift();
|
||||
var bits:uint = 0;
|
||||
if (keys.length>1) {
|
||||
bits = parseInt(keys[1]);
|
||||
}
|
||||
return new HMAC(getHash(keys[0]), bits);
|
||||
}
|
||||
|
||||
|
||||
public static function getMAC(name:String):MAC {
|
||||
|
||||
var keys:Array = name.split("-");
|
||||
if (keys[0]=="mac") keys.shift();
|
||||
var bits:uint = 0;
|
||||
if (keys.length > 1) {
|
||||
bits = parseInt(keys[1]);
|
||||
}
|
||||
return new MAC(getHash(keys[0]), bits);
|
||||
}
|
||||
|
||||
|
||||
public static function getPad(name:String):IPad {
|
||||
switch(name) {
|
||||
case "null":
|
||||
return new NullPad;
|
||||
case "pkcs5":
|
||||
default:
|
||||
return new PKCS5;
|
||||
}
|
||||
}
|
||||
|
||||
/** mostly useless.
|
||||
*/
|
||||
public static function getRSA(E:String, M:String):RSAKey {
|
||||
return RSAKey.parsePublicKey(M,E);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3235
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* X509Certificate
|
||||
*
|
||||
* A representation for a X509 Certificate, with
|
||||
* methods to parse, verify and sign it.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.cert {
|
||||
import com.hurlant.crypto.hash.IHash;
|
||||
import com.hurlant.crypto.hash.MD2;
|
||||
import com.hurlant.crypto.hash.MD5;
|
||||
import com.hurlant.crypto.hash.SHA1;
|
||||
import com.hurlant.crypto.rsa.RSAKey;
|
||||
import com.hurlant.util.ArrayUtil;
|
||||
import com.hurlant.util.Base64;
|
||||
import com.hurlant.util.der.ByteString;
|
||||
import com.hurlant.util.der.DER;
|
||||
import com.hurlant.util.der.OID;
|
||||
import com.hurlant.util.der.ObjectIdentifier;
|
||||
import com.hurlant.util.der.PEM;
|
||||
import com.hurlant.util.der.PrintableString;
|
||||
import com.hurlant.util.der.Sequence;
|
||||
import com.hurlant.util.der.Type;
|
||||
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public class X509Certificate {
|
||||
private var _loaded:Boolean;
|
||||
private var _param:*;
|
||||
private var _obj:Object;
|
||||
public function X509Certificate(p:*) {
|
||||
_loaded = false;
|
||||
_param = p;
|
||||
// lazy initialization, to avoid unnecessary parsing of every builtin CA at start-up.
|
||||
}
|
||||
private function load():void {
|
||||
if (_loaded) return;
|
||||
var p:* = _param;
|
||||
var b:ByteArray;
|
||||
if (p is String) {
|
||||
b = PEM.readCertIntoArray(p as String);
|
||||
} else if (p is ByteArray) {
|
||||
b = p;
|
||||
}
|
||||
if (b!=null) {
|
||||
_obj = DER.parse(b, Type.TLS_CERT);
|
||||
_loaded = true;
|
||||
} else {
|
||||
throw new Error("Invalid x509 Certificate parameter: "+p);
|
||||
}
|
||||
}
|
||||
public function isSigned(store:X509CertificateCollection, CAs:X509CertificateCollection, time:Date=null):Boolean {
|
||||
load();
|
||||
// check timestamps first. cheapest.
|
||||
if (time==null) {
|
||||
time = new Date;
|
||||
}
|
||||
var notBefore:Date = getNotBefore();
|
||||
var notAfter:Date = getNotAfter();
|
||||
if (time.getTime()<notBefore.getTime()) return false; // cert isn't born yet.
|
||||
if (time.getTime()>notAfter.getTime()) return false; // cert died of old age.
|
||||
// check signature.
|
||||
var subject:String = getIssuerPrincipal();
|
||||
// try from CA first, since they're treated better.
|
||||
var parent:X509Certificate = CAs.getCertificate(subject);
|
||||
var parentIsAuthoritative:Boolean = false;
|
||||
if (parent == null) {
|
||||
parent = store.getCertificate(subject);
|
||||
if (parent == null) {
|
||||
return false; // issuer not found
|
||||
}
|
||||
} else {
|
||||
parentIsAuthoritative = true;
|
||||
}
|
||||
if (parent == this) { // pathological case. avoid infinite loop
|
||||
return false; // isSigned() returns false if we're self-signed.
|
||||
}
|
||||
if (!(parentIsAuthoritative&&parent.isSelfSigned(time)) &&
|
||||
!parent.isSigned(store, CAs, time)) {
|
||||
return false;
|
||||
}
|
||||
var key:RSAKey = parent.getPublicKey();
|
||||
return verifyCertificate(key);
|
||||
}
|
||||
public function isSelfSigned(time:Date):Boolean {
|
||||
load();
|
||||
|
||||
var key:RSAKey = getPublicKey();
|
||||
return verifyCertificate(key);
|
||||
}
|
||||
private function verifyCertificate(key:RSAKey):Boolean {
|
||||
var algo:String = getAlgorithmIdentifier();
|
||||
var hash:IHash;
|
||||
var oid:String;
|
||||
switch (algo) {
|
||||
case OID.SHA1_WITH_RSA_ENCRYPTION:
|
||||
hash = new SHA1;
|
||||
oid = OID.SHA1_ALGORITHM;
|
||||
break;
|
||||
case OID.MD2_WITH_RSA_ENCRYPTION:
|
||||
hash = new MD2;
|
||||
oid = OID.MD2_ALGORITHM;
|
||||
break;
|
||||
case OID.MD5_WITH_RSA_ENCRYPTION:
|
||||
hash = new MD5;
|
||||
oid = OID.MD5_ALGORITHM;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
var data:ByteArray = _obj.signedCertificate_bin;
|
||||
var buf:ByteArray = new ByteArray;
|
||||
key.verify(_obj.encrypted, buf, _obj.encrypted.length);
|
||||
buf.position=0;
|
||||
data = hash.hash(data);
|
||||
var obj:Object = DER.parse(buf, Type.RSA_SIGNATURE);
|
||||
if (obj.algorithm.algorithmId.toString() != oid) {
|
||||
return false; // wrong algorithm
|
||||
}
|
||||
if (!ArrayUtil.equals(obj.hash, data)) {
|
||||
return false; // hashes don't match
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This isn't used anywhere so far.
|
||||
* It would become useful if we started to offer facilities
|
||||
* to generate and sign X509 certificates.
|
||||
*
|
||||
* @param key
|
||||
* @param algo
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
private function signCertificate(key:RSAKey, algo:String):ByteArray {
|
||||
var hash:IHash;
|
||||
var oid:String;
|
||||
switch (algo) {
|
||||
case OID.SHA1_WITH_RSA_ENCRYPTION:
|
||||
hash = new SHA1;
|
||||
oid = OID.SHA1_ALGORITHM;
|
||||
break;
|
||||
case OID.MD2_WITH_RSA_ENCRYPTION:
|
||||
hash = new MD2;
|
||||
oid = OID.MD2_ALGORITHM;
|
||||
break;
|
||||
case OID.MD5_WITH_RSA_ENCRYPTION:
|
||||
hash = new MD5;
|
||||
oid = OID.MD5_ALGORITHM;
|
||||
break;
|
||||
default:
|
||||
return null
|
||||
}
|
||||
var data:ByteArray = _obj.signedCertificate_bin;
|
||||
data = hash.hash(data);
|
||||
var seq1:Sequence = new Sequence;
|
||||
seq1[0] = new Sequence;
|
||||
seq1[0][0] = new ObjectIdentifier(0,0, oid);
|
||||
seq1[0][1] = null;
|
||||
seq1[1] = new ByteString;
|
||||
seq1[1].writeBytes(data);
|
||||
data = seq1.toDER();
|
||||
var buf:ByteArray = new ByteArray;
|
||||
key.sign(data, buf, data.length);
|
||||
return buf;
|
||||
}
|
||||
|
||||
public function getPublicKey():RSAKey {
|
||||
load();
|
||||
var pk:ByteArray = _obj.signedCertificate.subjectPublicKeyInfo.subjectPublicKey as ByteArray;
|
||||
pk.position = 0;
|
||||
var rsaKey:Object = DER.parse(pk, [{name:"N"},{name:"E"}]);
|
||||
return new RSAKey(rsaKey.N, rsaKey.E.valueOf());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a subject principal, as an opaque base64 string.
|
||||
* This is only used as a hash key for known certificates.
|
||||
*
|
||||
* Note that this assumes X509 DER-encoded certificates are uniquely encoded,
|
||||
* as we look for exact matches between Issuer and Subject fields.
|
||||
*
|
||||
*/
|
||||
public function getSubjectPrincipal():String {
|
||||
load();
|
||||
return Base64.encodeByteArray(_obj.signedCertificate.subject_bin);
|
||||
}
|
||||
/**
|
||||
* Returns an issuer principal, as an opaque base64 string.
|
||||
* This is only used to quickly find matching parent certificates.
|
||||
*
|
||||
* Note that this assumes X509 DER-encoded certificates are uniquely encoded,
|
||||
* as we look for exact matches between Issuer and Subject fields.
|
||||
*
|
||||
*/
|
||||
public function getIssuerPrincipal():String {
|
||||
load();
|
||||
return Base64.encodeByteArray(_obj.signedCertificate.issuer_bin);
|
||||
}
|
||||
public function getAlgorithmIdentifier():String {
|
||||
return _obj.algorithmIdentifier.algorithmId.toString();
|
||||
}
|
||||
public function getNotBefore():Date {
|
||||
return _obj.signedCertificate.validity.notBefore.date;
|
||||
}
|
||||
public function getNotAfter():Date {
|
||||
return _obj.signedCertificate.validity.notAfter.date;
|
||||
}
|
||||
|
||||
public function getCommonName():String {
|
||||
var subject:Sequence = _obj.signedCertificate.subject;
|
||||
return (subject.findAttributeValue(OID.COMMON_NAME) as PrintableString).getString();
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* X509CertificateCollection
|
||||
*
|
||||
* A class to store and index X509 Certificates by Subject.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.cert {
|
||||
|
||||
public class X509CertificateCollection {
|
||||
|
||||
private var _map:Object;
|
||||
|
||||
public function X509CertificateCollection() {
|
||||
_map = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostly meant for built-in CA loading.
|
||||
* This entry-point allows to index CAs without parsing them.
|
||||
*
|
||||
* @param name A friendly name. not currently used
|
||||
* @param subject base64 DER encoded Subject principal for the Cert
|
||||
* @param pem PEM encoded certificate data
|
||||
*
|
||||
*/
|
||||
public function addPEMCertificate(name:String, subject:String, pem:String):void {
|
||||
_map[subject] = new X509Certificate(pem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a X509 certificate to the collection.
|
||||
* This call will force the certificate to be parsed.
|
||||
*
|
||||
* @param cert A X509 certificate
|
||||
*
|
||||
*/
|
||||
public function addCertificate(cert:X509Certificate):void {
|
||||
var subject:String = cert.getSubjectPrincipal();
|
||||
_map[subject] = cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a X509 Certificate present in the collection, given
|
||||
* a base64 DER encoded X500 Subject principal
|
||||
*
|
||||
* @param subject A Base64 DER-encoded Subject principal
|
||||
* @return A matching certificate, or null.
|
||||
*
|
||||
*/
|
||||
public function getCertificate(subject:String):X509Certificate {
|
||||
return _map[subject];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 60
|
||||
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash
|
||||
END
|
||||
MAC.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 67
|
||||
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/MAC.as
|
||||
END
|
||||
IHMAC.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 69
|
||||
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/IHMAC.as
|
||||
END
|
||||
MD2.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 67
|
||||
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/MD2.as
|
||||
END
|
||||
SHA224.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 69
|
||||
/svn/!svn/ver/3/trunk/as3crypto/src/com/hurlant/crypto/hash/SHA224.as
|
||||
END
|
||||
MD5.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 67
|
||||
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/MD5.as
|
||||
END
|
||||
SHABase.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 71
|
||||
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/SHABase.as
|
||||
END
|
||||
SHA256.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 70
|
||||
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/SHA256.as
|
||||
END
|
||||
HMAC.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 68
|
||||
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/HMAC.as
|
||||
END
|
||||
IHash.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 69
|
||||
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/IHash.as
|
||||
END
|
||||
SHA1.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 68
|
||||
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/SHA1.as
|
||||
END
|
||||
@@ -0,0 +1,368 @@
|
||||
10
|
||||
|
||||
dir
|
||||
28
|
||||
http://as3crypto.googlecode.com/svn/trunk/as3crypto/src/com/hurlant/crypto/hash
|
||||
http://as3crypto.googlecode.com/svn
|
||||
|
||||
|
||||
|
||||
2009-06-04T23:35:21.192697Z
|
||||
28
|
||||
sh0rtwave
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
395c722c-794e-0410-9327-f1aa524df581
|
||||
|
||||
MAC.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-11-07T06:59:45.000000Z
|
||||
0bedba9be73ae40adeb26ca35c8237f4
|
||||
2009-06-04T23:35:21.192697Z
|
||||
28
|
||||
sh0rtwave
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
3559
|
||||
|
||||
IHMAC.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-11-07T06:59:45.000000Z
|
||||
dac8b7d8c849fe11f90ec290aa5dedf0
|
||||
2009-06-04T23:35:21.192697Z
|
||||
28
|
||||
sh0rtwave
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
599
|
||||
|
||||
MD2.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-11-07T06:59:45.000000Z
|
||||
73bf759d445a65186512066a103dbb45
|
||||
2009-06-04T23:35:21.192697Z
|
||||
28
|
||||
sh0rtwave
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
3811
|
||||
|
||||
SHA224.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-11-07T06:59:45.000000Z
|
||||
026d3e96099de7100c1d49012720d6f9
|
||||
2008-06-22T05:51:59.360556Z
|
||||
3
|
||||
henrit
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
604
|
||||
|
||||
MD5.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-11-07T06:59:45.000000Z
|
||||
60211f6583ee826e2a17ad03605aa7b4
|
||||
2009-06-04T23:35:21.192697Z
|
||||
28
|
||||
sh0rtwave
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
6965
|
||||
|
||||
SHABase.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-11-07T06:59:45.000000Z
|
||||
aa1101bf874f26cd364cf16fb7dff6c7
|
||||
2009-06-04T23:35:21.192697Z
|
||||
28
|
||||
sh0rtwave
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1495
|
||||
|
||||
SHA256.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-11-07T06:59:45.000000Z
|
||||
c14bc0555970db81a87f5d2b60e4288c
|
||||
2009-06-04T23:35:21.192697Z
|
||||
28
|
||||
sh0rtwave
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
3459
|
||||
|
||||
HMAC.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-11-07T06:59:45.000000Z
|
||||
c96c9bc0e0b64eed7e2d8c27dc29c561
|
||||
2009-06-04T23:35:21.192697Z
|
||||
28
|
||||
sh0rtwave
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2132
|
||||
|
||||
IHash.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-11-07T06:59:45.000000Z
|
||||
71f45750c456debd7ef1f74e6db9dc23
|
||||
2009-06-04T23:35:21.192697Z
|
||||
28
|
||||
sh0rtwave
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
445
|
||||
|
||||
SHA1.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2009-11-07T06:59:45.000000Z
|
||||
ba97b95bebda5bdd3fe2063e9c7e21cd
|
||||
2009-06-04T23:35:21.192697Z
|
||||
28
|
||||
sh0rtwave
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2642
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* HMAC
|
||||
*
|
||||
* An ActionScript 3 implementation of HMAC, Keyed-Hashing for Message
|
||||
* Authentication, as defined by RFC-2104
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Hex;
|
||||
|
||||
public class HMAC implements IHMAC
|
||||
{
|
||||
private var hash:IHash;
|
||||
private var bits:uint;
|
||||
|
||||
/**
|
||||
* Create a HMAC object, using a Hash function, and
|
||||
* optionally a number of bits to return.
|
||||
* The HMAC will be truncated to that size if needed.
|
||||
*/
|
||||
public function HMAC(hash:IHash, bits:uint=0) {
|
||||
this.hash = hash;
|
||||
this.bits = bits;
|
||||
}
|
||||
|
||||
|
||||
public function getHashSize():uint {
|
||||
if (bits!=0) {
|
||||
return bits/8;
|
||||
} else {
|
||||
return hash.getHashSize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a HMAC using a key and some data.
|
||||
* It doesn't modify either, and returns a new ByteArray with the HMAC value.
|
||||
*/
|
||||
public function compute(key:ByteArray, data:ByteArray):ByteArray {
|
||||
var hashKey:ByteArray;
|
||||
if (key.length>hash.getInputSize()) {
|
||||
hashKey = hash.hash(key);
|
||||
} else {
|
||||
hashKey = new ByteArray;
|
||||
hashKey.writeBytes(key);
|
||||
}
|
||||
while (hashKey.length<hash.getInputSize()) {
|
||||
hashKey[hashKey.length]=0;
|
||||
}
|
||||
var innerKey:ByteArray = new ByteArray;
|
||||
var outerKey:ByteArray = new ByteArray;
|
||||
for (var i:uint=0;i<hashKey.length;i++) {
|
||||
innerKey[i] = hashKey[i] ^ 0x36;
|
||||
outerKey[i] = hashKey[i] ^ 0x5c;
|
||||
}
|
||||
// inner + data
|
||||
innerKey.position = hashKey.length;
|
||||
innerKey.writeBytes(data);
|
||||
var innerHash:ByteArray = hash.hash(innerKey);
|
||||
// outer + innerHash
|
||||
outerKey.position = hashKey.length;
|
||||
outerKey.writeBytes(innerHash);
|
||||
var outerHash:ByteArray = hash.hash(outerKey);
|
||||
if (bits>0 && bits<8*outerHash.length) {
|
||||
outerHash.length = bits/8;
|
||||
}
|
||||
return outerHash;
|
||||
}
|
||||
public function dispose():void {
|
||||
hash = null;
|
||||
bits = 0;
|
||||
}
|
||||
public function toString():String {
|
||||
return "hmac-"+(bits>0?bits+"-":"")+hash.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* HMAC
|
||||
*
|
||||
* An ActionScript 3 interface for HMAC & MAC
|
||||
* implementations.
|
||||
*
|
||||
* Loosely copyrighted by Bobby Parker
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public interface IHMAC
|
||||
{
|
||||
function getHashSize():uint;
|
||||
/**
|
||||
* Compute a HMAC using a key and some data.
|
||||
* It doesn't modify either, and returns a new ByteArray with the HMAC value.
|
||||
*/
|
||||
function compute(key:ByteArray, data:ByteArray):ByteArray;
|
||||
function dispose():void;
|
||||
function toString():String;
|
||||
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* IHash
|
||||
*
|
||||
* An interface for each hash function to implement
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public interface IHash
|
||||
{
|
||||
function getInputSize():uint;
|
||||
function getHashSize():uint;
|
||||
function hash(src:ByteArray):ByteArray;
|
||||
function toString():String;
|
||||
function getPadSize():int;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* MAC
|
||||
*
|
||||
* An ActionScript 3 implementation of MAC, Message Authentication Code
|
||||
* for use with SSL 3.0.
|
||||
* Loosely copyrighted by Bobby Parker.
|
||||
* As3crypto copyrighted by Henri Torgemane.
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Hex;
|
||||
|
||||
public class MAC implements IHMAC
|
||||
{
|
||||
private var hash:IHash;
|
||||
private var bits:uint;
|
||||
private var pad_1:ByteArray;
|
||||
private var pad_2:ByteArray;
|
||||
private var innerHash:ByteArray;
|
||||
private var outerHash:ByteArray;
|
||||
private var outerKey:ByteArray;
|
||||
private var innerKey:ByteArray;
|
||||
/**
|
||||
* Create a MAC object (for SSL 3.0 ) and
|
||||
* optionally a number of bits to return.
|
||||
* The MAC will be truncated to that size if needed.
|
||||
*/
|
||||
public function MAC(hash:IHash, bits:uint=0) {
|
||||
this.hash = hash;
|
||||
this.bits = bits;
|
||||
innerHash = new ByteArray();
|
||||
outerHash = new ByteArray();
|
||||
innerKey = new ByteArray();
|
||||
outerKey = new ByteArray();
|
||||
|
||||
|
||||
if (hash != null) {
|
||||
var pad_size:int = hash.getPadSize();
|
||||
pad_1 = new ByteArray();
|
||||
pad_2 = new ByteArray();
|
||||
|
||||
for (var x:int = 0; x < pad_size; x++) {
|
||||
pad_1.writeByte(0x36);
|
||||
pad_2.writeByte(0x5c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setPadSize(pad_size:int) : void { }
|
||||
|
||||
public function getHashSize():uint {
|
||||
if (bits!=0) {
|
||||
return bits/8;
|
||||
} else {
|
||||
return hash.getHashSize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute a MAC using a key and some data.
|
||||
*
|
||||
*/
|
||||
public function compute(key:ByteArray, data:ByteArray):ByteArray {
|
||||
// take that incoming key and do hash(key + pad_2 + hash(key + pad_1 + sequence + length + record)
|
||||
// note that data = (sequence + type + length + record)
|
||||
|
||||
if (pad_1 == null) {
|
||||
var pad_size:int = hash.getPadSize();
|
||||
pad_1 = new ByteArray();
|
||||
pad_2 = new ByteArray();
|
||||
|
||||
for (var x:int = 0; x < pad_size; x++) {
|
||||
pad_1.writeByte(0x36);
|
||||
pad_2.writeByte(0x5c);
|
||||
}
|
||||
}
|
||||
|
||||
// Do some preliminary checking on stuff
|
||||
/*
|
||||
if (key.length > hash.getInputSize()) {
|
||||
hashKey = hash.hash(key);
|
||||
} else {
|
||||
hashKey = new ByteArray;
|
||||
hashKey.writeBytes(key);
|
||||
}
|
||||
|
||||
while (hashKey.length < hash.getInputSize() ) {
|
||||
hashKey[hashKey.length] = 0;
|
||||
} */
|
||||
// Henri's conventions work just fine here..
|
||||
|
||||
innerKey.length = 0;
|
||||
outerKey.length = 0;
|
||||
// trace("MAC Key: " + Hex.fromArray(key));
|
||||
// trace("Key Length: " + key.length);
|
||||
// trace("Pad_1 : " + Hex.fromArray(pad_1));
|
||||
// inner hash calc
|
||||
innerKey.writeBytes(key);
|
||||
innerKey.writeBytes(pad_1);
|
||||
innerKey.writeBytes(data);
|
||||
// trace("MAC Inner Key: " + Hex.fromArray(innerKey));
|
||||
|
||||
innerHash = hash.hash(innerKey);
|
||||
// trace("MAC Inner Hash: " + Hex.fromArray(innerHash));
|
||||
|
||||
// outer hash calc
|
||||
outerKey.writeBytes(key);
|
||||
outerKey.writeBytes(pad_2);
|
||||
outerKey.writeBytes(innerHash);
|
||||
|
||||
// trace("MAC Outer Key: " + Hex.fromArray(outerKey));
|
||||
outerHash = hash.hash(outerKey);
|
||||
|
||||
|
||||
if (bits > 0 && bits < 8*outerHash.length) {
|
||||
outerHash.length = bits/8;
|
||||
}
|
||||
|
||||
// trace("MAC for record: " + Hex.fromArray(outerHash));
|
||||
return outerHash;
|
||||
|
||||
}
|
||||
|
||||
public function dispose():void {
|
||||
hash = null;
|
||||
bits = 0;
|
||||
}
|
||||
public function toString():String {
|
||||
return "mac-"+(bits>0?bits+"-":"")+hash.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* MD2
|
||||
*
|
||||
* An ActionScript 3 implementation of the RSA Data Security, Inc MD2 Message
|
||||
* Digest Algorithm, as defined in RFC 1319
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*
|
||||
* Excerpt from http://en.wikipedia.org/wiki/MD2:
|
||||
* >
|
||||
* > Rogier and Chauvaud (1997) described collisions of MD2's compression function,
|
||||
* > although they were unable to extend the attack to the full MD2.
|
||||
* >
|
||||
* > In 2004, MD2 was shown to be vulnerable to a preimage attack with time
|
||||
* > complexity equivalent to 2104 applications of the compression function
|
||||
* > (Muller, 2004).
|
||||
* > The author concludes, "MD2 can no longer be considered a secure one-way
|
||||
* > hash function".
|
||||
*
|
||||
* also, this implementaton is quite slow.
|
||||
*/
|
||||
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public class MD2 implements IHash
|
||||
{
|
||||
public static const HASH_SIZE:int = 16;
|
||||
public var pad_size:int = 48; // probably will never get used, only here for SSL 3.0 support
|
||||
|
||||
private static const S:Array = [ // PI Digits
|
||||
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 ];
|
||||
|
||||
public function getInputSize():uint
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
public function getPadSize():int {
|
||||
return pad_size;
|
||||
}
|
||||
|
||||
public function getHashSize():uint
|
||||
{
|
||||
return HASH_SIZE;
|
||||
}
|
||||
|
||||
public function hash(src:ByteArray):ByteArray
|
||||
{
|
||||
var savedLength:uint = src.length;
|
||||
|
||||
// 3.1 Step 1. Padding
|
||||
var i:uint = (16-src.length%16) || 16;
|
||||
do {
|
||||
src[src.length]=i;
|
||||
} while (src.length%16!=0);
|
||||
|
||||
// 3.2 Step 2. Checksum
|
||||
var len:uint = src.length;
|
||||
var checksum:ByteArray = new ByteArray;
|
||||
var L:uint = 0;
|
||||
for (i = 0;i<len;i+=16) {
|
||||
for (var j:uint=0;j<16;j++) {
|
||||
L = checksum[j] ^= S[src[i+j] ^ L];
|
||||
}
|
||||
}
|
||||
src.position = src.length;
|
||||
src.writeBytes(checksum);
|
||||
len += 16;
|
||||
|
||||
// 3.3 Step 3. MD Buffer
|
||||
var X:ByteArray = new ByteArray;
|
||||
|
||||
// 3.4 Process Message
|
||||
for (i=0;i<len;i+=16) {
|
||||
|
||||
/* Copy block i into X */
|
||||
for (j=0;j<16;j++) {
|
||||
X[32+j] = (X[16+j] = src[i+j])^X[j];
|
||||
}
|
||||
var t:uint=0;
|
||||
/* Do 18 rounds */
|
||||
for (j=0;j<18;j++) {
|
||||
/* Round j. */
|
||||
for (var k:uint=0;k<48;k++) {
|
||||
X[k] = t = X[k]^S[t];
|
||||
}
|
||||
t = (t+j)&0xff;
|
||||
}
|
||||
}
|
||||
// 3.5 Step 5. Output
|
||||
X.length = 16;
|
||||
// restore original length;
|
||||
src.length = savedLength;
|
||||
return X;
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
return "md2";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* MD5
|
||||
*
|
||||
* An ActionScript 3 implementation of the RSA Data Security, Inc. MD5 Message
|
||||
* Digest Algorithm, as defined in RFC 1321.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from
|
||||
* A JavaScript implementation of the same.
|
||||
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
|
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||
*
|
||||
* Note:
|
||||
* This algorithm should not be your first choice for new developements, but is
|
||||
* included to allow interoperability with existing codes and protocols.
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import flash.utils.Endian;
|
||||
|
||||
public class MD5 implements IHash
|
||||
{
|
||||
public static const HASH_SIZE:int = 16;
|
||||
public var pad_size:int = 48;
|
||||
|
||||
public function getInputSize():uint
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
public function getHashSize():uint
|
||||
{
|
||||
return HASH_SIZE;
|
||||
}
|
||||
|
||||
public function getPadSize():int
|
||||
{
|
||||
return pad_size;
|
||||
}
|
||||
|
||||
public function hash(src:ByteArray):ByteArray
|
||||
{
|
||||
var len:uint = src.length *8;
|
||||
var savedEndian:String = src.endian;
|
||||
// pad to nearest int.
|
||||
while (src.length%4!=0) {
|
||||
src[src.length]=0;
|
||||
}
|
||||
// convert ByteArray to an array of uint
|
||||
src.position=0;
|
||||
var a:Array = [];
|
||||
src.endian=Endian.LITTLE_ENDIAN
|
||||
for (var i:uint=0;i<src.length;i+=4) {
|
||||
a.push(src.readUnsignedInt());
|
||||
}
|
||||
var h:Array = core_md5(a, len);
|
||||
var out:ByteArray = new ByteArray;
|
||||
out.endian=Endian.LITTLE_ENDIAN;
|
||||
for (i=0;i<4;i++) {
|
||||
out.writeUnsignedInt(h[i]);
|
||||
}
|
||||
// restore length!
|
||||
src.length = len/8;
|
||||
src.endian = savedEndian;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private function core_md5(x:Array, len:uint):Array {
|
||||
/* append padding */
|
||||
x[len >> 5] |= 0x80 << ((len) % 32);
|
||||
x[(((len + 64) >>> 9) << 4) + 14] = len;
|
||||
|
||||
var a:uint = 0x67452301; // 1732584193;
|
||||
var b:uint = 0xEFCDAB89; //-271733879;
|
||||
var c:uint = 0x98BADCFE; //-1732584194;
|
||||
var d:uint = 0x10325476; // 271733878;
|
||||
|
||||
for(var i:uint = 0; i < x.length; i += 16)
|
||||
{
|
||||
x[i]||=0; x[i+1]||=0; x[i+2]||=0; x[i+3]||=0;
|
||||
x[i+4]||=0; x[i+5]||=0; x[i+6]||=0; x[i+7]||=0;
|
||||
x[i+8]||=0; x[i+9]||=0; x[i+10]||=0; x[i+11]||=0;
|
||||
x[i+12]||=0; x[i+13]||=0; x[i+14]||=0; x[i+15]||=0;
|
||||
|
||||
var olda:uint = a;
|
||||
var oldb:uint = b;
|
||||
var oldc:uint = c;
|
||||
var oldd:uint = d;
|
||||
|
||||
a = ff(a, b, c, d, x[i+ 0], 7 , 0xD76AA478);
|
||||
d = ff(d, a, b, c, x[i+ 1], 12, 0xE8C7B756);
|
||||
c = ff(c, d, a, b, x[i+ 2], 17, 0x242070DB);
|
||||
b = ff(b, c, d, a, x[i+ 3], 22, 0xC1BDCEEE);
|
||||
a = ff(a, b, c, d, x[i+ 4], 7 , 0xF57C0FAF);
|
||||
d = ff(d, a, b, c, x[i+ 5], 12, 0x4787C62A);
|
||||
c = ff(c, d, a, b, x[i+ 6], 17, 0xA8304613);
|
||||
b = ff(b, c, d, a, x[i+ 7], 22, 0xFD469501);
|
||||
a = ff(a, b, c, d, x[i+ 8], 7 , 0x698098D8);
|
||||
d = ff(d, a, b, c, x[i+ 9], 12, 0x8B44F7AF);
|
||||
c = ff(c, d, a, b, x[i+10], 17, 0xFFFF5BB1);
|
||||
b = ff(b, c, d, a, x[i+11], 22, 0x895CD7BE);
|
||||
a = ff(a, b, c, d, x[i+12], 7 , 0x6B901122);
|
||||
d = ff(d, a, b, c, x[i+13], 12, 0xFD987193);
|
||||
c = ff(c, d, a, b, x[i+14], 17, 0xA679438E);
|
||||
b = ff(b, c, d, a, x[i+15], 22, 0x49B40821);
|
||||
|
||||
a = gg(a, b, c, d, x[i+ 1], 5 , 0xf61e2562);
|
||||
d = gg(d, a, b, c, x[i+ 6], 9 , 0xc040b340);
|
||||
c = gg(c, d, a, b, x[i+11], 14, 0x265e5a51);
|
||||
b = gg(b, c, d, a, x[i+ 0], 20, 0xe9b6c7aa);
|
||||
a = gg(a, b, c, d, x[i+ 5], 5 , 0xd62f105d);
|
||||
d = gg(d, a, b, c, x[i+10], 9 , 0x2441453);
|
||||
c = gg(c, d, a, b, x[i+15], 14, 0xd8a1e681);
|
||||
b = gg(b, c, d, a, x[i+ 4], 20, 0xe7d3fbc8);
|
||||
a = gg(a, b, c, d, x[i+ 9], 5 , 0x21e1cde6);
|
||||
d = gg(d, a, b, c, x[i+14], 9 , 0xc33707d6);
|
||||
c = gg(c, d, a, b, x[i+ 3], 14, 0xf4d50d87);
|
||||
b = gg(b, c, d, a, x[i+ 8], 20, 0x455a14ed);
|
||||
a = gg(a, b, c, d, x[i+13], 5 , 0xa9e3e905);
|
||||
d = gg(d, a, b, c, x[i+ 2], 9 , 0xfcefa3f8);
|
||||
c = gg(c, d, a, b, x[i+ 7], 14, 0x676f02d9);
|
||||
b = gg(b, c, d, a, x[i+12], 20, 0x8d2a4c8a);
|
||||
|
||||
a = hh(a, b, c, d, x[i+ 5], 4 , 0xfffa3942);
|
||||
d = hh(d, a, b, c, x[i+ 8], 11, 0x8771f681);
|
||||
c = hh(c, d, a, b, x[i+11], 16, 0x6d9d6122);
|
||||
b = hh(b, c, d, a, x[i+14], 23, 0xfde5380c);
|
||||
a = hh(a, b, c, d, x[i+ 1], 4 , 0xa4beea44);
|
||||
d = hh(d, a, b, c, x[i+ 4], 11, 0x4bdecfa9);
|
||||
c = hh(c, d, a, b, x[i+ 7], 16, 0xf6bb4b60);
|
||||
b = hh(b, c, d, a, x[i+10], 23, 0xbebfbc70);
|
||||
a = hh(a, b, c, d, x[i+13], 4 , 0x289b7ec6);
|
||||
d = hh(d, a, b, c, x[i+ 0], 11, 0xeaa127fa);
|
||||
c = hh(c, d, a, b, x[i+ 3], 16, 0xd4ef3085);
|
||||
b = hh(b, c, d, a, x[i+ 6], 23, 0x4881d05);
|
||||
a = hh(a, b, c, d, x[i+ 9], 4 , 0xd9d4d039);
|
||||
d = hh(d, a, b, c, x[i+12], 11, 0xe6db99e5);
|
||||
c = hh(c, d, a, b, x[i+15], 16, 0x1fa27cf8);
|
||||
b = hh(b, c, d, a, x[i+ 2], 23, 0xc4ac5665);
|
||||
|
||||
a = ii(a, b, c, d, x[i+ 0], 6 , 0xf4292244);
|
||||
d = ii(d, a, b, c, x[i+ 7], 10, 0x432aff97);
|
||||
c = ii(c, d, a, b, x[i+14], 15, 0xab9423a7);
|
||||
b = ii(b, c, d, a, x[i+ 5], 21, 0xfc93a039);
|
||||
a = ii(a, b, c, d, x[i+12], 6 , 0x655b59c3);
|
||||
d = ii(d, a, b, c, x[i+ 3], 10, 0x8f0ccc92);
|
||||
c = ii(c, d, a, b, x[i+10], 15, 0xffeff47d);
|
||||
b = ii(b, c, d, a, x[i+ 1], 21, 0x85845dd1);
|
||||
a = ii(a, b, c, d, x[i+ 8], 6 , 0x6fa87e4f);
|
||||
d = ii(d, a, b, c, x[i+15], 10, 0xfe2ce6e0);
|
||||
c = ii(c, d, a, b, x[i+ 6], 15, 0xa3014314);
|
||||
b = ii(b, c, d, a, x[i+13], 21, 0x4e0811a1);
|
||||
a = ii(a, b, c, d, x[i+ 4], 6 , 0xf7537e82);
|
||||
d = ii(d, a, b, c, x[i+11], 10, 0xbd3af235);
|
||||
c = ii(c, d, a, b, x[i+ 2], 15, 0x2ad7d2bb);
|
||||
b = ii(b, c, d, a, x[i+ 9], 21, 0xeb86d391);
|
||||
|
||||
a += olda;
|
||||
b += oldb;
|
||||
c += oldc;
|
||||
d += oldd;
|
||||
|
||||
}
|
||||
return [ a, b, c, d ];
|
||||
}
|
||||
|
||||
/*
|
||||
* Bitwise rotate a 32-bit number to the left.
|
||||
*/
|
||||
private function rol(num:uint, cnt:uint):uint
|
||||
{
|
||||
return (num << cnt) | (num >>> (32 - cnt));
|
||||
}
|
||||
|
||||
/*
|
||||
* These functions implement the four basic operations the algorithm uses.
|
||||
*/
|
||||
private function cmn(q:uint, a:uint, b:uint, x:uint, s:uint, t:uint):uint {
|
||||
return rol(a + q + x + t, s) + b;
|
||||
}
|
||||
private function ff(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
|
||||
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
|
||||
}
|
||||
private function gg(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
|
||||
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
|
||||
}
|
||||
private function hh(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
|
||||
return cmn(b ^ c ^ d, a, b, x, s, t);
|
||||
}
|
||||
private function ii(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
|
||||
return cmn(c ^ (b | (~d)), a, b, x, s, t);
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return "md5";
|
||||
}
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* SHA1
|
||||
*
|
||||
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-1, as defined
|
||||
* in FIPS PUB 180-1
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from:
|
||||
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
|
||||
* in FIPS PUB 180-1
|
||||
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
|
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
|
||||
|
||||
public class SHA1 extends SHABase implements IHash
|
||||
{
|
||||
public static const HASH_SIZE:int = 20;
|
||||
|
||||
public override function getHashSize():uint {
|
||||
return HASH_SIZE;
|
||||
}
|
||||
|
||||
protected override function core(x:Array, len:uint):Array
|
||||
{
|
||||
/* append padding */
|
||||
x[len >> 5] |= 0x80 << (24 - len % 32);
|
||||
x[((len + 64 >> 9) << 4) + 15] = len;
|
||||
|
||||
var w:Array = [];
|
||||
var a:uint = 0x67452301; //1732584193;
|
||||
var b:uint = 0xEFCDAB89; //-271733879;
|
||||
var c:uint = 0x98BADCFE; //-1732584194;
|
||||
var d:uint = 0x10325476; //271733878;
|
||||
var e:uint = 0xC3D2E1F0; //-1009589776;
|
||||
|
||||
for(var i:uint = 0; i < x.length; i += 16)
|
||||
{
|
||||
|
||||
var olda:uint = a;
|
||||
var oldb:uint = b;
|
||||
var oldc:uint = c;
|
||||
var oldd:uint = d;
|
||||
var olde:uint = e;
|
||||
|
||||
for(var j:uint = 0; j < 80; j++)
|
||||
{
|
||||
if (j < 16) {
|
||||
w[j] = x[i + j] || 0;
|
||||
} else {
|
||||
w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
|
||||
}
|
||||
var t:uint = rol(a,5) + ft(j,b,c,d) + e + w[j] + kt(j);
|
||||
e = d;
|
||||
d = c;
|
||||
c = rol(b, 30);
|
||||
b = a;
|
||||
a = t;
|
||||
}
|
||||
a += olda;
|
||||
b += oldb;
|
||||
c += oldc;
|
||||
d += oldd;
|
||||
e += olde;
|
||||
}
|
||||
return [ a, b, c, d, e ];
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Bitwise rotate a 32-bit number to the left.
|
||||
*/
|
||||
private function rol(num:uint, cnt:uint):uint
|
||||
{
|
||||
return (num << cnt) | (num >>> (32 - cnt));
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the appropriate triplet combination function for the current
|
||||
* iteration
|
||||
*/
|
||||
private function ft(t:uint, b:uint, c:uint, d:uint):uint
|
||||
{
|
||||
if(t < 20) return (b & c) | ((~b) & d);
|
||||
if(t < 40) return b ^ c ^ d;
|
||||
if(t < 60) return (b & c) | (b & d) | (c & d);
|
||||
return b ^ c ^ d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the appropriate additive constant for the current iteration
|
||||
*/
|
||||
private function kt(t:uint):uint
|
||||
{
|
||||
return (t < 20) ? 0x5A827999 : (t < 40) ? 0x6ED9EBA1 :
|
||||
(t < 60) ? 0x8F1BBCDC : 0xCA62C1D6;
|
||||
}
|
||||
public override function toString():String {
|
||||
return "sha1";
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* SHA224
|
||||
*
|
||||
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-224, as defined
|
||||
* in FIPS PUB 180-2
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
public class SHA224 extends SHA256
|
||||
{
|
||||
function SHA224() {
|
||||
h = [
|
||||
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
|
||||
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
|
||||
];
|
||||
}
|
||||
|
||||
public override function getHashSize():uint {
|
||||
return 28;
|
||||
}
|
||||
public override function toString():String {
|
||||
return "sha224";
|
||||
}
|
||||
}
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* SHA256
|
||||
*
|
||||
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-256, as defined
|
||||
* in FIPS PUB 180-2
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from:
|
||||
* A JavaScript implementation of the Secure Hash Standard
|
||||
* Version 0.3 Copyright Angel Marin 2003-2004 - http://anmar.eu.org/
|
||||
* Derived from:
|
||||
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
|
||||
* in FIPS PUB 180-1
|
||||
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
|
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
|
||||
|
||||
public class SHA256 extends SHABase implements IHash
|
||||
{
|
||||
|
||||
protected static const 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];
|
||||
protected var h:Array = [
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
];
|
||||
|
||||
public function SHA256(){
|
||||
}
|
||||
|
||||
public override function getHashSize():uint
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
protected override function core(x:Array, len:uint):Array {
|
||||
/* append padding */
|
||||
x[len >> 5] |= 0x80 << (24 - len % 32);
|
||||
x[((len + 64 >> 9) << 4) + 15] = len;
|
||||
|
||||
var w:Array = [];
|
||||
var a:uint = h[0];
|
||||
var b:uint = h[1];
|
||||
var c:uint = h[2];
|
||||
var d:uint = h[3];
|
||||
var e:uint = h[4];
|
||||
var f:uint = h[5];
|
||||
var g:uint = h[6];
|
||||
var h:uint = h[7];
|
||||
|
||||
for (var i:uint=0; i<x.length; i+=16) {
|
||||
var olda:uint = a;
|
||||
var oldb:uint = b;
|
||||
var oldc:uint = c;
|
||||
var oldd:uint = d;
|
||||
var olde:uint = e;
|
||||
var oldf:uint = f;
|
||||
var oldg:uint = g;
|
||||
var oldh:uint = h;
|
||||
|
||||
for (var j:uint=0; j<64; j++) {
|
||||
if (j<16) {
|
||||
w[j] = x[i+j] || 0;
|
||||
} else {
|
||||
var s0:uint = rrol(w[j-15],7)^rrol(w[j-15],18)^(w[j-15]>>>3);
|
||||
var s1:uint = rrol(w[j-2], 17)^rrol(w[j-2],19)^(w[j-2]>>>10);
|
||||
w[j] = w[j-16] + s0 + w[j-7] + s1;
|
||||
}
|
||||
var t2:uint = (rrol(a,2) ^ rrol(a,13) ^ rrol(a,22)) + ((a&b) ^ (a&c) ^ (b&c));
|
||||
var t1:uint = h + (rrol(e,6) ^ rrol(e,11) ^ rrol(e,25)) + ((e&f)^(g&~e)) + k[j] + w[j]
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
|
||||
}
|
||||
a += olda;
|
||||
b += oldb;
|
||||
c += oldc;
|
||||
d += oldd;
|
||||
e += olde;
|
||||
f += oldf;
|
||||
g += oldg;
|
||||
h += oldh;
|
||||
}
|
||||
return [ a,b,c,d,e,f,g,h ];
|
||||
}
|
||||
|
||||
/*
|
||||
* Bitwise rotate a 32-bit number to the right.
|
||||
*/
|
||||
protected function rrol(num:uint, cnt:uint):uint {
|
||||
return (num << (32-cnt)) | (num >>> cnt);
|
||||
}
|
||||
|
||||
public override function toString():String {
|
||||
return "sha256";
|
||||
}
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* SHABase
|
||||
*
|
||||
* An ActionScript 3 abstract class for the SHA family of hash functions
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import flash.utils.Endian;
|
||||
|
||||
public class SHABase implements IHash
|
||||
{
|
||||
public var pad_size:int = 40;
|
||||
public function getInputSize():uint
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
public function getHashSize():uint
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getPadSize():int
|
||||
{
|
||||
return pad_size;
|
||||
}
|
||||
|
||||
public function hash(src:ByteArray):ByteArray
|
||||
{
|
||||
var savedLength:uint = src.length;
|
||||
var savedEndian:String = src.endian;
|
||||
|
||||
src.endian = Endian.BIG_ENDIAN;
|
||||
var len:uint = savedLength *8;
|
||||
// pad to nearest int.
|
||||
while (src.length%4!=0) {
|
||||
src[src.length]=0;
|
||||
}
|
||||
// convert ByteArray to an array of uint
|
||||
src.position=0;
|
||||
var a:Array = [];
|
||||
for (var i:uint=0;i<src.length;i+=4) {
|
||||
a.push(src.readUnsignedInt());
|
||||
}
|
||||
var h:Array = core(a, len);
|
||||
var out:ByteArray = new ByteArray;
|
||||
var words:uint = getHashSize()/4;
|
||||
for (i=0;i<words;i++) {
|
||||
out.writeUnsignedInt(h[i]);
|
||||
}
|
||||
// unpad, to leave the source untouched.
|
||||
src.length = savedLength;
|
||||
src.endian = savedEndian;
|
||||
return out;
|
||||
}
|
||||
protected function core(x:Array, len:uint):Array {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return "sha";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* HMAC
|
||||
*
|
||||
* An ActionScript 3 implementation of HMAC, Keyed-Hashing for Message
|
||||
* Authentication, as defined by RFC-2104
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Hex;
|
||||
|
||||
public class HMAC implements IHMAC
|
||||
{
|
||||
private var hash:IHash;
|
||||
private var bits:uint;
|
||||
|
||||
/**
|
||||
* Create a HMAC object, using a Hash function, and
|
||||
* optionally a number of bits to return.
|
||||
* The HMAC will be truncated to that size if needed.
|
||||
*/
|
||||
public function HMAC(hash:IHash, bits:uint=0) {
|
||||
this.hash = hash;
|
||||
this.bits = bits;
|
||||
}
|
||||
|
||||
|
||||
public function getHashSize():uint {
|
||||
if (bits!=0) {
|
||||
return bits/8;
|
||||
} else {
|
||||
return hash.getHashSize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a HMAC using a key and some data.
|
||||
* It doesn't modify either, and returns a new ByteArray with the HMAC value.
|
||||
*/
|
||||
public function compute(key:ByteArray, data:ByteArray):ByteArray {
|
||||
var hashKey:ByteArray;
|
||||
if (key.length>hash.getInputSize()) {
|
||||
hashKey = hash.hash(key);
|
||||
} else {
|
||||
hashKey = new ByteArray;
|
||||
hashKey.writeBytes(key);
|
||||
}
|
||||
while (hashKey.length<hash.getInputSize()) {
|
||||
hashKey[hashKey.length]=0;
|
||||
}
|
||||
var innerKey:ByteArray = new ByteArray;
|
||||
var outerKey:ByteArray = new ByteArray;
|
||||
for (var i:uint=0;i<hashKey.length;i++) {
|
||||
innerKey[i] = hashKey[i] ^ 0x36;
|
||||
outerKey[i] = hashKey[i] ^ 0x5c;
|
||||
}
|
||||
// inner + data
|
||||
innerKey.position = hashKey.length;
|
||||
innerKey.writeBytes(data);
|
||||
var innerHash:ByteArray = hash.hash(innerKey);
|
||||
// outer + innerHash
|
||||
outerKey.position = hashKey.length;
|
||||
outerKey.writeBytes(innerHash);
|
||||
var outerHash:ByteArray = hash.hash(outerKey);
|
||||
if (bits>0 && bits<8*outerHash.length) {
|
||||
outerHash.length = bits/8;
|
||||
}
|
||||
return outerHash;
|
||||
}
|
||||
public function dispose():void {
|
||||
hash = null;
|
||||
bits = 0;
|
||||
}
|
||||
public function toString():String {
|
||||
return "hmac-"+(bits>0?bits+"-":"")+hash.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* HMAC
|
||||
*
|
||||
* An ActionScript 3 interface for HMAC & MAC
|
||||
* implementations.
|
||||
*
|
||||
* Loosely copyrighted by Bobby Parker
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public interface IHMAC
|
||||
{
|
||||
function getHashSize():uint;
|
||||
/**
|
||||
* Compute a HMAC using a key and some data.
|
||||
* It doesn't modify either, and returns a new ByteArray with the HMAC value.
|
||||
*/
|
||||
function compute(key:ByteArray, data:ByteArray):ByteArray;
|
||||
function dispose():void;
|
||||
function toString():String;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* IHash
|
||||
*
|
||||
* An interface for each hash function to implement
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public interface IHash
|
||||
{
|
||||
function getInputSize():uint;
|
||||
function getHashSize():uint;
|
||||
function hash(src:ByteArray):ByteArray;
|
||||
function toString():String;
|
||||
function getPadSize():int;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* MAC
|
||||
*
|
||||
* An ActionScript 3 implementation of MAC, Message Authentication Code
|
||||
* for use with SSL 3.0.
|
||||
* Loosely copyrighted by Bobby Parker.
|
||||
* As3crypto copyrighted by Henri Torgemane.
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Hex;
|
||||
|
||||
public class MAC implements IHMAC
|
||||
{
|
||||
private var hash:IHash;
|
||||
private var bits:uint;
|
||||
private var pad_1:ByteArray;
|
||||
private var pad_2:ByteArray;
|
||||
private var innerHash:ByteArray;
|
||||
private var outerHash:ByteArray;
|
||||
private var outerKey:ByteArray;
|
||||
private var innerKey:ByteArray;
|
||||
/**
|
||||
* Create a MAC object (for SSL 3.0 ) and
|
||||
* optionally a number of bits to return.
|
||||
* The MAC will be truncated to that size if needed.
|
||||
*/
|
||||
public function MAC(hash:IHash, bits:uint=0) {
|
||||
this.hash = hash;
|
||||
this.bits = bits;
|
||||
innerHash = new ByteArray();
|
||||
outerHash = new ByteArray();
|
||||
innerKey = new ByteArray();
|
||||
outerKey = new ByteArray();
|
||||
|
||||
|
||||
if (hash != null) {
|
||||
var pad_size:int = hash.getPadSize();
|
||||
pad_1 = new ByteArray();
|
||||
pad_2 = new ByteArray();
|
||||
|
||||
for (var x:int = 0; x < pad_size; x++) {
|
||||
pad_1.writeByte(0x36);
|
||||
pad_2.writeByte(0x5c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setPadSize(pad_size:int) : void { }
|
||||
|
||||
public function getHashSize():uint {
|
||||
if (bits!=0) {
|
||||
return bits/8;
|
||||
} else {
|
||||
return hash.getHashSize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute a MAC using a key and some data.
|
||||
*
|
||||
*/
|
||||
public function compute(key:ByteArray, data:ByteArray):ByteArray {
|
||||
// take that incoming key and do hash(key + pad_2 + hash(key + pad_1 + sequence + length + record)
|
||||
// note that data = (sequence + type + length + record)
|
||||
|
||||
if (pad_1 == null) {
|
||||
var pad_size:int = hash.getPadSize();
|
||||
pad_1 = new ByteArray();
|
||||
pad_2 = new ByteArray();
|
||||
|
||||
for (var x:int = 0; x < pad_size; x++) {
|
||||
pad_1.writeByte(0x36);
|
||||
pad_2.writeByte(0x5c);
|
||||
}
|
||||
}
|
||||
|
||||
// Do some preliminary checking on stuff
|
||||
/*
|
||||
if (key.length > hash.getInputSize()) {
|
||||
hashKey = hash.hash(key);
|
||||
} else {
|
||||
hashKey = new ByteArray;
|
||||
hashKey.writeBytes(key);
|
||||
}
|
||||
|
||||
while (hashKey.length < hash.getInputSize() ) {
|
||||
hashKey[hashKey.length] = 0;
|
||||
} */
|
||||
// Henri's conventions work just fine here..
|
||||
|
||||
innerKey.length = 0;
|
||||
outerKey.length = 0;
|
||||
// trace("MAC Key: " + Hex.fromArray(key));
|
||||
// trace("Key Length: " + key.length);
|
||||
// trace("Pad_1 : " + Hex.fromArray(pad_1));
|
||||
// inner hash calc
|
||||
innerKey.writeBytes(key);
|
||||
innerKey.writeBytes(pad_1);
|
||||
innerKey.writeBytes(data);
|
||||
// trace("MAC Inner Key: " + Hex.fromArray(innerKey));
|
||||
|
||||
innerHash = hash.hash(innerKey);
|
||||
// trace("MAC Inner Hash: " + Hex.fromArray(innerHash));
|
||||
|
||||
// outer hash calc
|
||||
outerKey.writeBytes(key);
|
||||
outerKey.writeBytes(pad_2);
|
||||
outerKey.writeBytes(innerHash);
|
||||
|
||||
// trace("MAC Outer Key: " + Hex.fromArray(outerKey));
|
||||
outerHash = hash.hash(outerKey);
|
||||
|
||||
|
||||
if (bits > 0 && bits < 8*outerHash.length) {
|
||||
outerHash.length = bits/8;
|
||||
}
|
||||
|
||||
// trace("MAC for record: " + Hex.fromArray(outerHash));
|
||||
return outerHash;
|
||||
|
||||
}
|
||||
|
||||
public function dispose():void {
|
||||
hash = null;
|
||||
bits = 0;
|
||||
}
|
||||
public function toString():String {
|
||||
return "mac-"+(bits>0?bits+"-":"")+hash.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* MD2
|
||||
*
|
||||
* An ActionScript 3 implementation of the RSA Data Security, Inc MD2 Message
|
||||
* Digest Algorithm, as defined in RFC 1319
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*
|
||||
* Excerpt from http://en.wikipedia.org/wiki/MD2:
|
||||
* >
|
||||
* > Rogier and Chauvaud (1997) described collisions of MD2's compression function,
|
||||
* > although they were unable to extend the attack to the full MD2.
|
||||
* >
|
||||
* > In 2004, MD2 was shown to be vulnerable to a preimage attack with time
|
||||
* > complexity equivalent to 2104 applications of the compression function
|
||||
* > (Muller, 2004).
|
||||
* > The author concludes, "MD2 can no longer be considered a secure one-way
|
||||
* > hash function".
|
||||
*
|
||||
* also, this implementaton is quite slow.
|
||||
*/
|
||||
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public class MD2 implements IHash
|
||||
{
|
||||
public static const HASH_SIZE:int = 16;
|
||||
public var pad_size:int = 48; // probably will never get used, only here for SSL 3.0 support
|
||||
|
||||
private static const S:Array = [ // PI Digits
|
||||
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 ];
|
||||
|
||||
|
||||
public function MD2() { }
|
||||
|
||||
public function getInputSize():uint
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
public function getPadSize():int {
|
||||
return pad_size;
|
||||
}
|
||||
|
||||
public function getHashSize():uint
|
||||
{
|
||||
return HASH_SIZE;
|
||||
}
|
||||
|
||||
public function hash(src:ByteArray):ByteArray
|
||||
{
|
||||
var savedLength:uint = src.length;
|
||||
|
||||
// 3.1 Step 1. Padding
|
||||
var i:uint = (16-src.length%16) || 16;
|
||||
do {
|
||||
src[src.length]=i;
|
||||
} while (src.length%16!=0);
|
||||
|
||||
// 3.2 Step 2. Checksum
|
||||
var len:uint = src.length;
|
||||
var checksum:ByteArray = new ByteArray;
|
||||
var L:uint = 0;
|
||||
for (i = 0;i<len;i+=16) {
|
||||
for (var j:uint=0;j<16;j++) {
|
||||
L = checksum[j] ^= S[src[i+j] ^ L];
|
||||
}
|
||||
}
|
||||
src.position = src.length;
|
||||
src.writeBytes(checksum);
|
||||
len += 16;
|
||||
|
||||
// 3.3 Step 3. MD Buffer
|
||||
var X:ByteArray = new ByteArray;
|
||||
|
||||
// 3.4 Process Message
|
||||
for (i=0;i<len;i+=16) {
|
||||
|
||||
/* Copy block i into X */
|
||||
for (j=0;j<16;j++) {
|
||||
X[32+j] = (X[16+j] = src[i+j])^X[j];
|
||||
}
|
||||
var t:uint=0;
|
||||
/* Do 18 rounds */
|
||||
for (j=0;j<18;j++) {
|
||||
/* Round j. */
|
||||
for (var k:uint=0;k<48;k++) {
|
||||
X[k] = t = X[k]^S[t];
|
||||
}
|
||||
t = (t+j)&0xff;
|
||||
}
|
||||
}
|
||||
// 3.5 Step 5. Output
|
||||
X.length = 16;
|
||||
// restore original length;
|
||||
src.length = savedLength;
|
||||
return X;
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
return "md2";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* MD5
|
||||
*
|
||||
* An ActionScript 3 implementation of the RSA Data Security, Inc. MD5 Message
|
||||
* Digest Algorithm, as defined in RFC 1321.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from
|
||||
* A JavaScript implementation of the same.
|
||||
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
|
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||
*
|
||||
* Note:
|
||||
* This algorithm should not be your first choice for new developements, but is
|
||||
* included to allow interoperability with existing codes and protocols.
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import flash.utils.Endian;
|
||||
|
||||
public class MD5 implements IHash
|
||||
{
|
||||
public static const HASH_SIZE:int = 16;
|
||||
public var pad_size:int = 48;
|
||||
|
||||
public function MD5() { }
|
||||
|
||||
public function getInputSize():uint
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
public function getHashSize():uint
|
||||
{
|
||||
return HASH_SIZE;
|
||||
}
|
||||
|
||||
public function getPadSize():int
|
||||
{
|
||||
return pad_size;
|
||||
}
|
||||
|
||||
public function hash(src:ByteArray):ByteArray
|
||||
{
|
||||
var len:uint = src.length *8;
|
||||
var savedEndian:String = src.endian;
|
||||
// pad to nearest int.
|
||||
while (src.length%4!=0) {
|
||||
src[src.length]=0;
|
||||
}
|
||||
// convert ByteArray to an array of uint
|
||||
src.position=0;
|
||||
var a:Array = [];
|
||||
src.endian=Endian.LITTLE_ENDIAN
|
||||
for (var i:uint=0;i<src.length;i+=4) {
|
||||
a.push(src.readUnsignedInt());
|
||||
}
|
||||
var h:Array = core_md5(a, len);
|
||||
var out:ByteArray = new ByteArray;
|
||||
out.endian=Endian.LITTLE_ENDIAN;
|
||||
for (i=0;i<4;i++) {
|
||||
out.writeUnsignedInt(h[i]);
|
||||
}
|
||||
// restore length!
|
||||
src.length = len/8;
|
||||
src.endian = savedEndian;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private function core_md5(x:Array, len:uint):Array {
|
||||
/* append padding */
|
||||
x[len >> 5] |= 0x80 << ((len) % 32);
|
||||
x[(((len + 64) >>> 9) << 4) + 14] = len;
|
||||
|
||||
var a:uint = 0x67452301; // 1732584193;
|
||||
var b:uint = 0xEFCDAB89; //-271733879;
|
||||
var c:uint = 0x98BADCFE; //-1732584194;
|
||||
var d:uint = 0x10325476; // 271733878;
|
||||
|
||||
for(var i:uint = 0; i < x.length; i += 16)
|
||||
{
|
||||
x[i]||=0; x[i+1]||=0; x[i+2]||=0; x[i+3]||=0;
|
||||
x[i+4]||=0; x[i+5]||=0; x[i+6]||=0; x[i+7]||=0;
|
||||
x[i+8]||=0; x[i+9]||=0; x[i+10]||=0; x[i+11]||=0;
|
||||
x[i+12]||=0; x[i+13]||=0; x[i+14]||=0; x[i+15]||=0;
|
||||
|
||||
var olda:uint = a;
|
||||
var oldb:uint = b;
|
||||
var oldc:uint = c;
|
||||
var oldd:uint = d;
|
||||
|
||||
a = ff(a, b, c, d, x[i+ 0], 7 , 0xD76AA478);
|
||||
d = ff(d, a, b, c, x[i+ 1], 12, 0xE8C7B756);
|
||||
c = ff(c, d, a, b, x[i+ 2], 17, 0x242070DB);
|
||||
b = ff(b, c, d, a, x[i+ 3], 22, 0xC1BDCEEE);
|
||||
a = ff(a, b, c, d, x[i+ 4], 7 , 0xF57C0FAF);
|
||||
d = ff(d, a, b, c, x[i+ 5], 12, 0x4787C62A);
|
||||
c = ff(c, d, a, b, x[i+ 6], 17, 0xA8304613);
|
||||
b = ff(b, c, d, a, x[i+ 7], 22, 0xFD469501);
|
||||
a = ff(a, b, c, d, x[i+ 8], 7 , 0x698098D8);
|
||||
d = ff(d, a, b, c, x[i+ 9], 12, 0x8B44F7AF);
|
||||
c = ff(c, d, a, b, x[i+10], 17, 0xFFFF5BB1);
|
||||
b = ff(b, c, d, a, x[i+11], 22, 0x895CD7BE);
|
||||
a = ff(a, b, c, d, x[i+12], 7 , 0x6B901122);
|
||||
d = ff(d, a, b, c, x[i+13], 12, 0xFD987193);
|
||||
c = ff(c, d, a, b, x[i+14], 17, 0xA679438E);
|
||||
b = ff(b, c, d, a, x[i+15], 22, 0x49B40821);
|
||||
|
||||
a = gg(a, b, c, d, x[i+ 1], 5 , 0xf61e2562);
|
||||
d = gg(d, a, b, c, x[i+ 6], 9 , 0xc040b340);
|
||||
c = gg(c, d, a, b, x[i+11], 14, 0x265e5a51);
|
||||
b = gg(b, c, d, a, x[i+ 0], 20, 0xe9b6c7aa);
|
||||
a = gg(a, b, c, d, x[i+ 5], 5 , 0xd62f105d);
|
||||
d = gg(d, a, b, c, x[i+10], 9 , 0x2441453);
|
||||
c = gg(c, d, a, b, x[i+15], 14, 0xd8a1e681);
|
||||
b = gg(b, c, d, a, x[i+ 4], 20, 0xe7d3fbc8);
|
||||
a = gg(a, b, c, d, x[i+ 9], 5 , 0x21e1cde6);
|
||||
d = gg(d, a, b, c, x[i+14], 9 , 0xc33707d6);
|
||||
c = gg(c, d, a, b, x[i+ 3], 14, 0xf4d50d87);
|
||||
b = gg(b, c, d, a, x[i+ 8], 20, 0x455a14ed);
|
||||
a = gg(a, b, c, d, x[i+13], 5 , 0xa9e3e905);
|
||||
d = gg(d, a, b, c, x[i+ 2], 9 , 0xfcefa3f8);
|
||||
c = gg(c, d, a, b, x[i+ 7], 14, 0x676f02d9);
|
||||
b = gg(b, c, d, a, x[i+12], 20, 0x8d2a4c8a);
|
||||
|
||||
a = hh(a, b, c, d, x[i+ 5], 4 , 0xfffa3942);
|
||||
d = hh(d, a, b, c, x[i+ 8], 11, 0x8771f681);
|
||||
c = hh(c, d, a, b, x[i+11], 16, 0x6d9d6122);
|
||||
b = hh(b, c, d, a, x[i+14], 23, 0xfde5380c);
|
||||
a = hh(a, b, c, d, x[i+ 1], 4 , 0xa4beea44);
|
||||
d = hh(d, a, b, c, x[i+ 4], 11, 0x4bdecfa9);
|
||||
c = hh(c, d, a, b, x[i+ 7], 16, 0xf6bb4b60);
|
||||
b = hh(b, c, d, a, x[i+10], 23, 0xbebfbc70);
|
||||
a = hh(a, b, c, d, x[i+13], 4 , 0x289b7ec6);
|
||||
d = hh(d, a, b, c, x[i+ 0], 11, 0xeaa127fa);
|
||||
c = hh(c, d, a, b, x[i+ 3], 16, 0xd4ef3085);
|
||||
b = hh(b, c, d, a, x[i+ 6], 23, 0x4881d05);
|
||||
a = hh(a, b, c, d, x[i+ 9], 4 , 0xd9d4d039);
|
||||
d = hh(d, a, b, c, x[i+12], 11, 0xe6db99e5);
|
||||
c = hh(c, d, a, b, x[i+15], 16, 0x1fa27cf8);
|
||||
b = hh(b, c, d, a, x[i+ 2], 23, 0xc4ac5665);
|
||||
|
||||
a = ii(a, b, c, d, x[i+ 0], 6 , 0xf4292244);
|
||||
d = ii(d, a, b, c, x[i+ 7], 10, 0x432aff97);
|
||||
c = ii(c, d, a, b, x[i+14], 15, 0xab9423a7);
|
||||
b = ii(b, c, d, a, x[i+ 5], 21, 0xfc93a039);
|
||||
a = ii(a, b, c, d, x[i+12], 6 , 0x655b59c3);
|
||||
d = ii(d, a, b, c, x[i+ 3], 10, 0x8f0ccc92);
|
||||
c = ii(c, d, a, b, x[i+10], 15, 0xffeff47d);
|
||||
b = ii(b, c, d, a, x[i+ 1], 21, 0x85845dd1);
|
||||
a = ii(a, b, c, d, x[i+ 8], 6 , 0x6fa87e4f);
|
||||
d = ii(d, a, b, c, x[i+15], 10, 0xfe2ce6e0);
|
||||
c = ii(c, d, a, b, x[i+ 6], 15, 0xa3014314);
|
||||
b = ii(b, c, d, a, x[i+13], 21, 0x4e0811a1);
|
||||
a = ii(a, b, c, d, x[i+ 4], 6 , 0xf7537e82);
|
||||
d = ii(d, a, b, c, x[i+11], 10, 0xbd3af235);
|
||||
c = ii(c, d, a, b, x[i+ 2], 15, 0x2ad7d2bb);
|
||||
b = ii(b, c, d, a, x[i+ 9], 21, 0xeb86d391);
|
||||
|
||||
a += olda;
|
||||
b += oldb;
|
||||
c += oldc;
|
||||
d += oldd;
|
||||
|
||||
}
|
||||
return [ a, b, c, d ];
|
||||
}
|
||||
|
||||
/*
|
||||
* Bitwise rotate a 32-bit number to the left.
|
||||
*/
|
||||
private function rol(num:uint, cnt:uint):uint
|
||||
{
|
||||
return (num << cnt) | (num >>> (32 - cnt));
|
||||
}
|
||||
|
||||
/*
|
||||
* These functions implement the four basic operations the algorithm uses.
|
||||
*/
|
||||
private function cmn(q:uint, a:uint, b:uint, x:uint, s:uint, t:uint):uint {
|
||||
return rol(a + q + x + t, s) + b;
|
||||
}
|
||||
private function ff(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
|
||||
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
|
||||
}
|
||||
private function gg(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
|
||||
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
|
||||
}
|
||||
private function hh(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
|
||||
return cmn(b ^ c ^ d, a, b, x, s, t);
|
||||
}
|
||||
private function ii(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
|
||||
return cmn(c ^ (b | (~d)), a, b, x, s, t);
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return "md5";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* SHA1
|
||||
*
|
||||
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-1, as defined
|
||||
* in FIPS PUB 180-1
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from:
|
||||
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
|
||||
* in FIPS PUB 180-1
|
||||
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
|
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
|
||||
|
||||
public class SHA1 extends SHABase implements IHash
|
||||
{
|
||||
public static const HASH_SIZE:int = 20;
|
||||
|
||||
public override function getHashSize():uint {
|
||||
return HASH_SIZE;
|
||||
}
|
||||
|
||||
protected override function core(x:Array, len:uint):Array
|
||||
{
|
||||
/* append padding */
|
||||
x[len >> 5] |= 0x80 << (24 - len % 32);
|
||||
x[((len + 64 >> 9) << 4) + 15] = len;
|
||||
|
||||
var w:Array = [];
|
||||
var a:uint = 0x67452301; //1732584193;
|
||||
var b:uint = 0xEFCDAB89; //-271733879;
|
||||
var c:uint = 0x98BADCFE; //-1732584194;
|
||||
var d:uint = 0x10325476; //271733878;
|
||||
var e:uint = 0xC3D2E1F0; //-1009589776;
|
||||
|
||||
for(var i:uint = 0; i < x.length; i += 16)
|
||||
{
|
||||
|
||||
var olda:uint = a;
|
||||
var oldb:uint = b;
|
||||
var oldc:uint = c;
|
||||
var oldd:uint = d;
|
||||
var olde:uint = e;
|
||||
|
||||
for(var j:uint = 0; j < 80; j++)
|
||||
{
|
||||
if (j < 16) {
|
||||
w[j] = x[i + j] || 0;
|
||||
} else {
|
||||
w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
|
||||
}
|
||||
var t:uint = rol(a,5) + ft(j,b,c,d) + e + w[j] + kt(j);
|
||||
e = d;
|
||||
d = c;
|
||||
c = rol(b, 30);
|
||||
b = a;
|
||||
a = t;
|
||||
}
|
||||
a += olda;
|
||||
b += oldb;
|
||||
c += oldc;
|
||||
d += oldd;
|
||||
e += olde;
|
||||
}
|
||||
return [ a, b, c, d, e ];
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Bitwise rotate a 32-bit number to the left.
|
||||
*/
|
||||
private function rol(num:uint, cnt:uint):uint
|
||||
{
|
||||
return (num << cnt) | (num >>> (32 - cnt));
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the appropriate triplet combination function for the current
|
||||
* iteration
|
||||
*/
|
||||
private function ft(t:uint, b:uint, c:uint, d:uint):uint
|
||||
{
|
||||
if(t < 20) return (b & c) | ((~b) & d);
|
||||
if(t < 40) return b ^ c ^ d;
|
||||
if(t < 60) return (b & c) | (b & d) | (c & d);
|
||||
return b ^ c ^ d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the appropriate additive constant for the current iteration
|
||||
*/
|
||||
private function kt(t:uint):uint
|
||||
{
|
||||
return (t < 20) ? 0x5A827999 : (t < 40) ? 0x6ED9EBA1 :
|
||||
(t < 60) ? 0x8F1BBCDC : 0xCA62C1D6;
|
||||
}
|
||||
public override function toString():String {
|
||||
return "sha1";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* SHA224
|
||||
*
|
||||
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-224, as defined
|
||||
* in FIPS PUB 180-2
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
public class SHA224 extends SHA256
|
||||
{
|
||||
function SHA224() {
|
||||
h = [
|
||||
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
|
||||
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
|
||||
];
|
||||
}
|
||||
|
||||
public override function getHashSize():uint {
|
||||
return 28;
|
||||
}
|
||||
public override function toString():String {
|
||||
return "sha224";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* SHA256
|
||||
*
|
||||
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-256, as defined
|
||||
* in FIPS PUB 180-2
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from:
|
||||
* A JavaScript implementation of the Secure Hash Standard
|
||||
* Version 0.3 Copyright Angel Marin 2003-2004 - http://anmar.eu.org/
|
||||
* Derived from:
|
||||
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
|
||||
* in FIPS PUB 180-1
|
||||
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
|
||||
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
|
||||
|
||||
public class SHA256 extends SHABase implements IHash
|
||||
{
|
||||
|
||||
protected static const 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];
|
||||
protected var h:Array = [
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
];
|
||||
|
||||
public function SHA256(){
|
||||
}
|
||||
|
||||
public override function getHashSize():uint
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
protected override function core(x:Array, len:uint):Array {
|
||||
/* append padding */
|
||||
x[len >> 5] |= 0x80 << (24 - len % 32);
|
||||
x[((len + 64 >> 9) << 4) + 15] = len;
|
||||
|
||||
var w:Array = [];
|
||||
var a:uint = h[0];
|
||||
var b:uint = h[1];
|
||||
var c:uint = h[2];
|
||||
var d:uint = h[3];
|
||||
var e:uint = h[4];
|
||||
var f:uint = h[5];
|
||||
var g:uint = h[6];
|
||||
var h:uint = h[7];
|
||||
|
||||
for (var i:uint=0; i<x.length; i+=16) {
|
||||
var olda:uint = a;
|
||||
var oldb:uint = b;
|
||||
var oldc:uint = c;
|
||||
var oldd:uint = d;
|
||||
var olde:uint = e;
|
||||
var oldf:uint = f;
|
||||
var oldg:uint = g;
|
||||
var oldh:uint = h;
|
||||
|
||||
for (var j:uint=0; j<64; j++) {
|
||||
if (j<16) {
|
||||
w[j] = x[i+j] || 0;
|
||||
} else {
|
||||
var s0:uint = rrol(w[j-15],7)^rrol(w[j-15],18)^(w[j-15]>>>3);
|
||||
var s1:uint = rrol(w[j-2], 17)^rrol(w[j-2],19)^(w[j-2]>>>10);
|
||||
w[j] = w[j-16] + s0 + w[j-7] + s1;
|
||||
}
|
||||
var t2:uint = (rrol(a,2) ^ rrol(a,13) ^ rrol(a,22)) + ((a&b) ^ (a&c) ^ (b&c));
|
||||
var t1:uint = h + (rrol(e,6) ^ rrol(e,11) ^ rrol(e,25)) + ((e&f)^(g&~e)) + k[j] + w[j]
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
|
||||
}
|
||||
a += olda;
|
||||
b += oldb;
|
||||
c += oldc;
|
||||
d += oldd;
|
||||
e += olde;
|
||||
f += oldf;
|
||||
g += oldg;
|
||||
h += oldh;
|
||||
}
|
||||
return [ a,b,c,d,e,f,g,h ];
|
||||
}
|
||||
|
||||
/*
|
||||
* Bitwise rotate a 32-bit number to the right.
|
||||
*/
|
||||
protected function rrol(num:uint, cnt:uint):uint {
|
||||
return (num << (32-cnt)) | (num >>> cnt);
|
||||
}
|
||||
|
||||
public override function toString():String {
|
||||
return "sha256";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* SHABase
|
||||
*
|
||||
* An ActionScript 3 abstract class for the SHA family of hash functions
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.hash
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import flash.utils.Endian;
|
||||
|
||||
public class SHABase implements IHash
|
||||
{
|
||||
|
||||
public function SHABase() { }
|
||||
|
||||
public var pad_size:int = 40;
|
||||
public function getInputSize():uint
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
public function getHashSize():uint
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getPadSize():int
|
||||
{
|
||||
return pad_size;
|
||||
}
|
||||
|
||||
public function hash(src:ByteArray):ByteArray
|
||||
{
|
||||
var savedLength:uint = src.length;
|
||||
var savedEndian:String = src.endian;
|
||||
|
||||
src.endian = Endian.BIG_ENDIAN;
|
||||
var len:uint = savedLength *8;
|
||||
// pad to nearest int.
|
||||
while (src.length%4!=0) {
|
||||
src[src.length]=0;
|
||||
}
|
||||
// convert ByteArray to an array of uint
|
||||
src.position=0;
|
||||
var a:Array = [];
|
||||
for (var i:uint=0;i<src.length;i+=4) {
|
||||
a.push(src.readUnsignedInt());
|
||||
}
|
||||
var h:Array = core(a, len);
|
||||
var out:ByteArray = new ByteArray;
|
||||
var words:uint = getHashSize()/4;
|
||||
for (i=0;i<words;i++) {
|
||||
out.writeUnsignedInt(h[i]);
|
||||
}
|
||||
// unpad, to leave the source untouched.
|
||||
src.length = savedLength;
|
||||
src.endian = savedEndian;
|
||||
return out;
|
||||
}
|
||||
protected function core(x:Array, len:uint):Array {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return "sha";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* ARC4
|
||||
*
|
||||
* An ActionScript 3 implementation of RC4
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from:
|
||||
* The jsbn library, Copyright (c) 2003-2005 Tom Wu
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.prng
|
||||
{
|
||||
import com.hurlant.crypto.symmetric.IStreamCipher;
|
||||
import com.hurlant.util.Memory;
|
||||
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public class ARC4 implements IPRNG, IStreamCipher {
|
||||
private var i:int = 0;
|
||||
private var j:int = 0;
|
||||
private var S:ByteArray;
|
||||
private const psize:uint = 256;
|
||||
public function ARC4(key:ByteArray = null){
|
||||
S = new ByteArray;
|
||||
if (key) {
|
||||
init(key);
|
||||
}
|
||||
}
|
||||
public function getPoolSize():uint {
|
||||
return psize;
|
||||
}
|
||||
public function init(key:ByteArray):void {
|
||||
var i:int;
|
||||
var j:int;
|
||||
var t:int;
|
||||
for (i=0; i<256; ++i) {
|
||||
S[i] = i;
|
||||
}
|
||||
j=0;
|
||||
for (i=0; i<256; ++i) {
|
||||
j = (j + S[i] + key[i%key.length]) & 255;
|
||||
t = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = t;
|
||||
}
|
||||
this.i=0;
|
||||
this.j=0;
|
||||
}
|
||||
public function next():uint {
|
||||
var t:int;
|
||||
i = (i+1)&255;
|
||||
j = (j+S[i])&255;
|
||||
t = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = t;
|
||||
return S[(t+S[i])&255];
|
||||
}
|
||||
|
||||
public function getBlockSize():uint {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function encrypt(block:ByteArray):void {
|
||||
var i:uint = 0;
|
||||
while (i<block.length) {
|
||||
block[i++] ^= next();
|
||||
}
|
||||
}
|
||||
public function decrypt(block:ByteArray):void {
|
||||
encrypt(block); // the beauty of XOR.
|
||||
}
|
||||
public function dispose():void {
|
||||
var i:uint = 0;
|
||||
if (S!=null) {
|
||||
for (i=0;i<S.length;i++) {
|
||||
S[i] = Math.random()*256;
|
||||
}
|
||||
S.length=0;
|
||||
S = null;
|
||||
}
|
||||
this.i = 0;
|
||||
this.j = 0;
|
||||
Memory.gc();
|
||||
}
|
||||
public function toString():String {
|
||||
return "rc4";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* IPRNG
|
||||
*
|
||||
* An interface for classes that can be used a pseudo-random number generators
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.prng
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public interface IPRNG {
|
||||
function getPoolSize():uint;
|
||||
function init(key:ByteArray):void;
|
||||
function next():uint;
|
||||
function dispose():void;
|
||||
function toString():String;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Random
|
||||
*
|
||||
* An ActionScript 3 implementation of a Random Number Generator
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from:
|
||||
* The jsbn library, Copyright (c) 2003-2005 Tom Wu
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.prng
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Memory;
|
||||
import flash.system.System;
|
||||
import flash.system.Capabilities;
|
||||
import flash.accessibility.AccessibilityProperties;
|
||||
import flash.display.SWFVersion;
|
||||
import flash.display.Stage;
|
||||
import flash.utils.getTimer;
|
||||
import flash.text.Font;
|
||||
|
||||
public class Random
|
||||
{
|
||||
private var state:IPRNG;
|
||||
private var ready:Boolean = false;
|
||||
private var pool:ByteArray;
|
||||
private var psize:int;
|
||||
private var pptr:int;
|
||||
private var seeded:Boolean = false;
|
||||
|
||||
public function Random(prng:Class = null) {
|
||||
if (prng==null) prng = ARC4;
|
||||
state = new prng as IPRNG;
|
||||
psize= state.getPoolSize();
|
||||
pool = new ByteArray;
|
||||
pptr = 0;
|
||||
while (pptr <psize) {
|
||||
var t:uint = 65536*Math.random();
|
||||
pool[pptr++] = t >>> 8;
|
||||
pool[pptr++] = t&255;
|
||||
}
|
||||
pptr=0;
|
||||
seed();
|
||||
}
|
||||
|
||||
public function seed(x:int = 0):void {
|
||||
if (x==0) {
|
||||
x = new Date().getTime();
|
||||
}
|
||||
pool[pptr++] ^= x & 255;
|
||||
pool[pptr++] ^= (x>>8)&255;
|
||||
pool[pptr++] ^= (x>>16)&255;
|
||||
pool[pptr++] ^= (x>>24)&255;
|
||||
pptr %= psize;
|
||||
seeded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gather anything we have that isn't entirely predictable:
|
||||
* - memory used
|
||||
* - system capabilities
|
||||
* - timing stuff
|
||||
* - installed fonts
|
||||
*/
|
||||
public function autoSeed():void {
|
||||
var b:ByteArray = new ByteArray;
|
||||
b.writeUnsignedInt(System.totalMemory);
|
||||
b.writeUTF(Capabilities.serverString);
|
||||
b.writeUnsignedInt(getTimer());
|
||||
b.writeUnsignedInt((new Date).getTime());
|
||||
var a:Array = Font.enumerateFonts(true);
|
||||
for each (var f:Font in a) {
|
||||
b.writeUTF(f.fontName);
|
||||
b.writeUTF(f.fontStyle);
|
||||
b.writeUTF(f.fontType);
|
||||
}
|
||||
b.position=0;
|
||||
while (b.bytesAvailable>=4) {
|
||||
seed(b.readUnsignedInt());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function nextBytes(buffer:ByteArray, length:int):void {
|
||||
while (length--) {
|
||||
buffer.writeByte(nextByte());
|
||||
}
|
||||
}
|
||||
public function nextByte():int {
|
||||
if (!ready) {
|
||||
if (!seeded) {
|
||||
autoSeed();
|
||||
}
|
||||
state.init(pool);
|
||||
pool.length = 0;
|
||||
pptr = 0;
|
||||
ready = true;
|
||||
}
|
||||
return state.next();
|
||||
}
|
||||
public function dispose():void {
|
||||
for (var i:uint=0;i<pool.length;i++) {
|
||||
pool[i] = Math.random()*256;
|
||||
}
|
||||
pool.length=0;
|
||||
pool = null;
|
||||
state.dispose();
|
||||
state = null;
|
||||
psize = 0;
|
||||
pptr = 0;
|
||||
Memory.gc();
|
||||
}
|
||||
public function toString():String {
|
||||
return "random-"+state.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* TLSPRF
|
||||
*
|
||||
* An ActionScript 3 implementation of a pseudo-random generator
|
||||
* that follows the TLS specification
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.prng
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.crypto.hash.HMAC;
|
||||
import com.hurlant.crypto.hash.MD5;
|
||||
import com.hurlant.crypto.hash.SHA1;
|
||||
import com.hurlant.util.Memory;
|
||||
import com.hurlant.util.Hex;
|
||||
import flash.utils.IDataOutput;
|
||||
|
||||
/**
|
||||
* There's "Random", and then there's TLS Random.
|
||||
* .
|
||||
* Still Pseudo-random, though.
|
||||
*/
|
||||
public class TLSPRF
|
||||
{
|
||||
// XXX WAY TOO MANY STRUCTURES HERE
|
||||
|
||||
// seed
|
||||
private var seed:ByteArray;
|
||||
// P_MD5's secret
|
||||
private var s1:ByteArray;
|
||||
// P_SHA-1's secret
|
||||
private var s2:ByteArray;
|
||||
// HMAC_MD5's A
|
||||
private var a1:ByteArray;
|
||||
// HMAC_SHA1's A
|
||||
private var a2:ByteArray;
|
||||
// Pool for P_MD5
|
||||
private var p1:ByteArray;
|
||||
// Pool for P_SHA1
|
||||
private var p2:ByteArray;
|
||||
// Data for HMAC_MD5
|
||||
private var d1:ByteArray;
|
||||
// Data for HMAC_SHA1
|
||||
private var d2:ByteArray;
|
||||
|
||||
|
||||
private var hmac_md5:HMAC;
|
||||
private var hmac_sha1:HMAC;
|
||||
|
||||
public function TLSPRF(secret:ByteArray, label:String, seed:ByteArray) {
|
||||
var l:int = Math.ceil(secret.length/2);
|
||||
var s1:ByteArray = new ByteArray;
|
||||
var s2:ByteArray = new ByteArray;
|
||||
s1.writeBytes(secret, 0, l);
|
||||
s2.writeBytes(secret, secret.length-l, l);
|
||||
var s:ByteArray = new ByteArray;
|
||||
s.writeUTFBytes(label);
|
||||
s.writeBytes(seed);
|
||||
this.seed = s;
|
||||
this.s1 = s1;
|
||||
this.s2 = s2;
|
||||
hmac_md5 = new HMAC(new MD5);
|
||||
hmac_sha1 = new HMAC(new SHA1);
|
||||
|
||||
this.a1 = hmac_md5.compute(s1, this.seed);
|
||||
this.a2 = hmac_sha1.compute(s2, this.seed);
|
||||
|
||||
p1 = new ByteArray;
|
||||
p2 = new ByteArray;
|
||||
|
||||
d1 = new ByteArray;
|
||||
d2 = new ByteArray;
|
||||
d1.position = MD5.HASH_SIZE;
|
||||
d1.writeBytes(this.seed);
|
||||
d2.position = SHA1.HASH_SIZE;
|
||||
d2.writeBytes(this.seed);
|
||||
}
|
||||
|
||||
// XXX HORRIBLY SLOW. REWRITE.
|
||||
public function nextBytes(buffer:IDataOutput, length:int):void {
|
||||
while (length--) {
|
||||
buffer.writeByte(nextByte());
|
||||
}
|
||||
}
|
||||
public function nextByte():int {
|
||||
if (p1.bytesAvailable==0) {
|
||||
more_md5();
|
||||
}
|
||||
if (p2.bytesAvailable==0) {
|
||||
more_sha1();
|
||||
}
|
||||
return p1.readUnsignedByte()^p2.readUnsignedByte();
|
||||
}
|
||||
public function dispose():void {
|
||||
seed = dba(seed);
|
||||
s1 = dba(s1);
|
||||
s2 = dba(s2);
|
||||
a1 = dba(a1);
|
||||
a2 = dba(a2);
|
||||
p1 = dba(p1);
|
||||
p2 = dba(p2);
|
||||
d1 = dba(d1);
|
||||
d2 = dba(d2);
|
||||
hmac_md5.dispose();
|
||||
hmac_md5 = null;
|
||||
hmac_sha1.dispose();
|
||||
hmac_sha1 = null;
|
||||
Memory.gc();
|
||||
}
|
||||
public function toString():String {
|
||||
return "tls-prf";
|
||||
}
|
||||
private function dba(ba:ByteArray):ByteArray {
|
||||
for (var i:uint=0;i<ba.length;i++) {
|
||||
ba[i]=0;
|
||||
}
|
||||
ba.length=0;
|
||||
return null;
|
||||
}
|
||||
private function more_md5():void {
|
||||
d1.position=0;
|
||||
d1.writeBytes(a1);
|
||||
var p:int = p1.position;
|
||||
var more:ByteArray = hmac_md5.compute(s1, d1);
|
||||
a1 = hmac_md5.compute(s1, a1);
|
||||
p1.writeBytes(more);
|
||||
p1.position=p;
|
||||
}
|
||||
private function more_sha1():void {
|
||||
d2.position=0;
|
||||
d2.writeBytes(a2);
|
||||
var p:int = p2.position;
|
||||
var more:ByteArray = hmac_sha1.compute(s2, d2);
|
||||
a2 = hmac_sha1.compute(s2, a2);
|
||||
p2.writeBytes(more);
|
||||
p2.position=p;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
/**
|
||||
* RSAKey
|
||||
*
|
||||
* An ActionScript 3 implementation of RSA + PKCS#1 (light version)
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from:
|
||||
* The jsbn library, Copyright (c) 2003-2005 Tom Wu
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.rsa
|
||||
{
|
||||
import com.hurlant.crypto.prng.Random;
|
||||
import com.hurlant.math.BigInteger;
|
||||
import com.hurlant.util.Memory;
|
||||
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.crypto.hash.IHash;
|
||||
import com.hurlant.util.Hex;
|
||||
import com.hurlant.util.der.DER;
|
||||
import com.hurlant.util.der.OID;
|
||||
import com.hurlant.util.ArrayUtil;
|
||||
import com.hurlant.util.der.Type;
|
||||
import com.hurlant.util.der.Sequence;
|
||||
import com.hurlant.util.der.ObjectIdentifier;
|
||||
import com.hurlant.util.der.ByteString;
|
||||
import com.hurlant.crypto.tls.TLSError;
|
||||
|
||||
/**
|
||||
* Current limitations:
|
||||
* exponent must be smaller than 2^31.
|
||||
*/
|
||||
public class RSAKey
|
||||
{
|
||||
// public key
|
||||
public var e:int; // public exponent. must be <2^31
|
||||
public var n:BigInteger; // modulus
|
||||
// private key
|
||||
public var d:BigInteger;
|
||||
// extended private key
|
||||
public var p:BigInteger;
|
||||
public var q:BigInteger;
|
||||
public var dmp1:BigInteger
|
||||
public var dmq1:BigInteger;
|
||||
public var coeff:BigInteger;
|
||||
// flags. flags are cool.
|
||||
protected var canDecrypt:Boolean;
|
||||
protected var canEncrypt:Boolean;
|
||||
|
||||
public function RSAKey(N:BigInteger, E:int,
|
||||
D:BigInteger=null,
|
||||
P:BigInteger = null, Q:BigInteger=null,
|
||||
DP:BigInteger=null, DQ:BigInteger=null,
|
||||
C:BigInteger=null) {
|
||||
|
||||
this.n = N;
|
||||
this.e = E;
|
||||
this.d = D;
|
||||
this.p = P;
|
||||
this.q = Q;
|
||||
this.dmp1 = DP;
|
||||
this.dmq1 = DQ;
|
||||
this.coeff = C;
|
||||
|
||||
// adjust a few flags.
|
||||
canEncrypt = (n!=null&&e!=0);
|
||||
canDecrypt = (canEncrypt&&d!=null);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static function parsePublicKey(N:String, E:String):RSAKey {
|
||||
return new RSAKey(new BigInteger(N, 16, true), parseInt(E,16));
|
||||
}
|
||||
public static function parsePrivateKey(N:String, E:String, D:String,
|
||||
P:String=null,Q:String=null, DMP1:String=null, DMQ1:String=null, IQMP:String=null):RSAKey {
|
||||
if (P==null) {
|
||||
return new RSAKey(new BigInteger(N,16, true), parseInt(E,16), new BigInteger(D,16, true));
|
||||
} else {
|
||||
return new RSAKey(new BigInteger(N,16, true), parseInt(E,16), new BigInteger(D,16, true),
|
||||
new BigInteger(P,16, true), new BigInteger(Q,16, true),
|
||||
new BigInteger(DMP1,16, true), new BigInteger(DMQ1, 16, true),
|
||||
new BigInteger(IQMP, 16, true));
|
||||
}
|
||||
}
|
||||
|
||||
public function getBlockSize():uint {
|
||||
return (n.bitLength()+7)/8;
|
||||
}
|
||||
public function dispose():void {
|
||||
e = 0;
|
||||
n.dispose();
|
||||
n = null;
|
||||
Memory.gc();
|
||||
}
|
||||
|
||||
public function encrypt(src:ByteArray, dst:ByteArray, length:uint, pad:Function=null):void {
|
||||
_encrypt(doPublic, src, dst, length, pad, 0x02);
|
||||
}
|
||||
public function decrypt(src:ByteArray, dst:ByteArray, length:uint, pad:Function=null):void {
|
||||
_decrypt(doPrivate2, src, dst, length, pad, 0x02);
|
||||
}
|
||||
|
||||
public function sign(src:ByteArray, dst:ByteArray, length:uint, pad:Function = null):void {
|
||||
_encrypt(doPrivate2, src, dst, length, pad, 0x01);
|
||||
}
|
||||
public function verify(src:ByteArray, dst:ByteArray, length:uint, pad:Function = null):void {
|
||||
_decrypt(doPublic, src, dst, length, pad, 0x01);
|
||||
}
|
||||
|
||||
|
||||
private function _encrypt(op:Function, src:ByteArray, dst:ByteArray, length:uint, pad:Function, padType:int):void {
|
||||
// adjust pad if needed
|
||||
if (pad==null) pad = pkcs1pad;
|
||||
// convert src to BigInteger
|
||||
if (src.position >= src.length) {
|
||||
src.position = 0;
|
||||
}
|
||||
var bl:uint = getBlockSize();
|
||||
var end:int = src.position + length;
|
||||
while (src.position<end) {
|
||||
var block:BigInteger = new BigInteger(pad(src, end, bl, padType), bl, true);
|
||||
var chunk:BigInteger = op(block);
|
||||
chunk.toArray(dst);
|
||||
}
|
||||
}
|
||||
private function _decrypt(op:Function, src:ByteArray, dst:ByteArray, length:uint, pad:Function, padType:int):void {
|
||||
// adjust pad if needed
|
||||
if (pad==null) pad = pkcs1unpad;
|
||||
|
||||
// convert src to BigInteger
|
||||
if (src.position >= src.length) {
|
||||
src.position = 0;
|
||||
}
|
||||
var bl:uint = getBlockSize();
|
||||
var end:int = src.position + length;
|
||||
while (src.position<end) {
|
||||
var block:BigInteger = new BigInteger(src, bl, true);
|
||||
var chunk:BigInteger = op(block);
|
||||
var b:ByteArray = pad(chunk, bl, padType);
|
||||
if (b == null)
|
||||
throw new TLSError( "Decrypt error - padding function returned null!", TLSError.decode_error );
|
||||
// if (b != null)
|
||||
dst.writeBytes(b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PKCS#1 pad. type 1 (0xff) or 2, random.
|
||||
* puts as much data from src into it, leaves what doesn't fit alone.
|
||||
*/
|
||||
private function pkcs1pad(src:ByteArray, end:int, n:uint, type:uint = 0x02):ByteArray {
|
||||
var out:ByteArray = new ByteArray;
|
||||
var p:uint = src.position;
|
||||
end = Math.min(end, src.length, p+n-11);
|
||||
src.position = end;
|
||||
var i:int = end-1;
|
||||
while (i>=p && n>11) {
|
||||
out[--n] = src[i--];
|
||||
}
|
||||
out[--n] = 0;
|
||||
if (type==0x02) { // type 2
|
||||
var rng:Random = new Random;
|
||||
var x:int = 0;
|
||||
while (n>2) {
|
||||
do {
|
||||
x = rng.nextByte();
|
||||
} while (x==0);
|
||||
out[--n] = x;
|
||||
}
|
||||
} else { // type 1
|
||||
while (n>2) {
|
||||
out[--n] = 0xFF;
|
||||
}
|
||||
}
|
||||
out[--n] = type;
|
||||
out[--n] = 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param src
|
||||
* @param n
|
||||
* @param type Not used.
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
private function pkcs1unpad(src:BigInteger, n:uint, type:uint = 0x02):ByteArray {
|
||||
var b:ByteArray = src.toByteArray();
|
||||
var out:ByteArray = new ByteArray;
|
||||
|
||||
b.position = 0;
|
||||
var i:int = 0;
|
||||
while (i<b.length && b[i]==0) ++i;
|
||||
if (b.length-i != n-1 || b[i]!=type) {
|
||||
trace("PKCS#1 unpad: i="+i+", expected b[i]=="+type+", got b[i]="+b[i].toString(16));
|
||||
return null;
|
||||
}
|
||||
++i;
|
||||
while (b[i]!=0) {
|
||||
if (++i>=b.length) {
|
||||
trace("PKCS#1 unpad: i="+i+", b[i-1]!=0 (="+b[i-1].toString(16)+")");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
while (++i < b.length) {
|
||||
out.writeByte(b[i]);
|
||||
}
|
||||
out.position = 0;
|
||||
return out;
|
||||
}
|
||||
/**
|
||||
* Raw pad.
|
||||
*/
|
||||
public function rawpad(src:ByteArray, end:int, n:uint, type:uint = 0):ByteArray {
|
||||
return src;
|
||||
}
|
||||
public function rawunpad(src:BigInteger, n:uint, type:uint = 0):ByteArray {
|
||||
return src.toByteArray();
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return "rsa";
|
||||
}
|
||||
|
||||
public function dump():String {
|
||||
var s:String= "N="+n.toString(16)+"\n"+
|
||||
"E="+e.toString(16)+"\n";
|
||||
if (canDecrypt) {
|
||||
s+="D="+d.toString(16)+"\n";
|
||||
if (p!=null && q!=null) {
|
||||
s+="P="+p.toString(16)+"\n";
|
||||
s+="Q="+q.toString(16)+"\n";
|
||||
s+="DMP1="+dmp1.toString(16)+"\n";
|
||||
s+="DMQ1="+dmq1.toString(16)+"\n";
|
||||
s+="IQMP="+coeff.toString(16)+"\n";
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* note: We should have a "nice" variant of this function that takes a callback,
|
||||
* and perform the computation is small fragments, to keep the web browser
|
||||
* usable.
|
||||
*
|
||||
* @param B
|
||||
* @param E
|
||||
* @return a new random private key B bits long, using public expt E
|
||||
*
|
||||
*/
|
||||
public static function generate(B:uint, E:String):RSAKey {
|
||||
var rng:Random = new Random;
|
||||
var qs:uint = B>>1;
|
||||
var key:RSAKey = new RSAKey(null,0,null);
|
||||
key.e = parseInt(E, 16);
|
||||
var ee:BigInteger = new BigInteger(E,16, true);
|
||||
for (;;) {
|
||||
for (;;) {
|
||||
key.p = bigRandom(B-qs, rng);
|
||||
if (key.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE)==0 &&
|
||||
key.p.isProbablePrime(10)) break;
|
||||
}
|
||||
for (;;) {
|
||||
key.q = bigRandom(qs, rng);
|
||||
if (key.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE)==0 &&
|
||||
key.q.isProbablePrime(10)) break;
|
||||
}
|
||||
if (key.p.compareTo(key.q)<=0) {
|
||||
var t:BigInteger = key.p;
|
||||
key.p = key.q;
|
||||
key.q = t;
|
||||
}
|
||||
var p1:BigInteger = key.p.subtract(BigInteger.ONE);
|
||||
var q1:BigInteger = key.q.subtract(BigInteger.ONE);
|
||||
var phi:BigInteger = p1.multiply(q1);
|
||||
if (phi.gcd(ee).compareTo(BigInteger.ONE)==0) {
|
||||
key.n = key.p.multiply(key.q);
|
||||
key.d = ee.modInverse(phi);
|
||||
key.dmp1 = key.d.mod(p1);
|
||||
key.dmq1 = key.d.mod(q1);
|
||||
key.coeff = key.q.modInverse(key.p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
protected static function bigRandom(bits:int, rnd:Random):BigInteger {
|
||||
if (bits<2) return BigInteger.nbv(1);
|
||||
var x:ByteArray = new ByteArray;
|
||||
rnd.nextBytes(x, (bits>>3));
|
||||
x.position = 0;
|
||||
var b:BigInteger = new BigInteger(x,0,true);
|
||||
b.primify(bits, 1);
|
||||
return b;
|
||||
}
|
||||
|
||||
protected function doPublic(x:BigInteger):BigInteger {
|
||||
return x.modPowInt(e, n);
|
||||
}
|
||||
|
||||
protected function doPrivate2(x:BigInteger):BigInteger {
|
||||
if (p==null && q==null) {
|
||||
return x.modPow(d,n);
|
||||
}
|
||||
|
||||
var xp:BigInteger = x.mod(p).modPow(dmp1, p);
|
||||
var xq:BigInteger = x.mod(q).modPow(dmq1, q);
|
||||
|
||||
while (xp.compareTo(xq)<0) {
|
||||
xp = xp.add(p);
|
||||
}
|
||||
var r:BigInteger = xp.subtract(xq).multiply(coeff).mod(p).multiply(q).add(xq);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
protected function doPrivate(x:BigInteger):BigInteger {
|
||||
if (p==null || q==null) {
|
||||
return x.modPow(d, n);
|
||||
}
|
||||
// TODO: re-calculate any missing CRT params
|
||||
var xp:BigInteger = x.mod(p).modPow(dmp1, p);
|
||||
var xq:BigInteger = x.mod(q).modPow(dmq1, q);
|
||||
|
||||
while (xp.compareTo(xq)<0) {
|
||||
xp = xp.add(p);
|
||||
}
|
||||
return xp.subtract(xq).multiply(coeff).mod(p).multiply(q).add(xq);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,375 @@
|
||||
/**
|
||||
* BlowFishKey
|
||||
*
|
||||
* An Actionscript 3 implementation of the BlowFish encryption algorithm,
|
||||
* as documented at http://www.schneier.com/blowfish.html
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from:
|
||||
* The Bouncy Castle Crypto package,
|
||||
* Copyright (c) 2000-2004 The Legion Of The Bouncy Castle
|
||||
* (http://www.bouncycastle.org)
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Memory;
|
||||
|
||||
public class BlowFishKey implements ISymmetricKey
|
||||
{
|
||||
|
||||
private static const KP:Array = [ 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0,
|
||||
0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5,
|
||||
0xB5470917, 0x9216D5D9, 0x8979FB1B ];
|
||||
|
||||
private static const KS0: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 ];
|
||||
|
||||
private static const KS1: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 ];
|
||||
|
||||
private static const KS2: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 ];
|
||||
|
||||
private static const KS3: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 ];
|
||||
|
||||
// ====================================
|
||||
// Useful constants
|
||||
// ====================================
|
||||
|
||||
private static const ROUNDS:uint = 16;
|
||||
private static const BLOCK_SIZE:uint = 8; // bytes = 64 bits
|
||||
private static const SBOX_SK:uint = 256;
|
||||
private static const P_SZ:uint = ROUNDS + 2;
|
||||
|
||||
private var S0:Array;
|
||||
private var S1:Array;
|
||||
private var S2:Array;
|
||||
private var S3:Array; // the s-boxes
|
||||
private var P:Array; // the p-array
|
||||
|
||||
private var key:ByteArray = null;
|
||||
|
||||
public function BlowFishKey(key:ByteArray) {
|
||||
this.key = key;
|
||||
setKey(key);
|
||||
}
|
||||
|
||||
public function getBlockSize():uint
|
||||
{
|
||||
return BLOCK_SIZE;
|
||||
}
|
||||
|
||||
public function decrypt(block:ByteArray, index:uint=0):void
|
||||
{
|
||||
decryptBlock(block, index, block, index);
|
||||
}
|
||||
|
||||
public function dispose():void
|
||||
{
|
||||
var i:uint=0;
|
||||
for (i=0;i<S0.length;i++) { S0[i]=0; }
|
||||
for (i=0;i<S1.length;i++) { S1[i]=0; }
|
||||
for (i=0;i<S2.length;i++) { S2[i]=0; }
|
||||
for (i=0;i<S3.length;i++) { S3[i]=0; }
|
||||
for (i=0;i<P.length;i++) { P[i]=0; }
|
||||
S0 = null;
|
||||
S1 = null;
|
||||
S2 = null;
|
||||
S3 = null;
|
||||
P = null;
|
||||
for (i=0;i<key.length;i++) {
|
||||
key[i]=0;
|
||||
}
|
||||
key.length = 0;
|
||||
key = null;
|
||||
Memory.gc();
|
||||
}
|
||||
|
||||
public function encrypt(block:ByteArray, index:uint=0):void
|
||||
{
|
||||
encryptBlock(block, index, block, index);
|
||||
}
|
||||
|
||||
// ==================================
|
||||
// Private Implementation
|
||||
// ==================================
|
||||
|
||||
private function F(x:uint):uint
|
||||
{
|
||||
return (((S0[(x >>> 24)] + S1[(x >>> 16) & 0xff]) ^ S2[(x >>> 8) & 0xff]) + S3[x & 0xff]);
|
||||
}
|
||||
|
||||
/**
|
||||
* apply the encryption cycle to each value pair in the table.
|
||||
*/
|
||||
private function processTable(xl:uint, xr:uint, table:Array):void
|
||||
{
|
||||
var size:uint = table.length;
|
||||
|
||||
for (var s:uint = 0; s < size; s += 2)
|
||||
{
|
||||
xl ^= P[0];
|
||||
|
||||
for (var i:uint = 1; i < ROUNDS; i += 2)
|
||||
{
|
||||
xr ^= F(xl) ^ P[i];
|
||||
xl ^= F(xr) ^ P[i + 1];
|
||||
}
|
||||
|
||||
xr ^= P[ROUNDS + 1];
|
||||
|
||||
table[s] = xr;
|
||||
table[s + 1] = xl;
|
||||
|
||||
xr = xl; // end of cycle swap
|
||||
xl = table[s];
|
||||
}
|
||||
}
|
||||
|
||||
private function setKey(key:ByteArray):void
|
||||
{
|
||||
/*
|
||||
* - comments are from _Applied Crypto_, Schneier, p338 please be
|
||||
* careful comparing the two, AC numbers the arrays from 1, the enclosed
|
||||
* code from 0.
|
||||
*
|
||||
* (1) Initialise the S-boxes and the P-array, with a fixed string This
|
||||
* string contains the hexadecimal digits of pi (3.141...)
|
||||
*/
|
||||
S0 = KS0.concat();
|
||||
S1 = KS1.concat();
|
||||
S2 = KS2.concat();
|
||||
S3 = KS3.concat();
|
||||
P = KP.concat();
|
||||
|
||||
/*
|
||||
* (2) Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with
|
||||
* the second 32-bits of the key, and so on for all bits of the key (up
|
||||
* to P[17]). Repeatedly cycle through the key bits until the entire
|
||||
* P-array has been XOR-ed with the key bits
|
||||
*/
|
||||
var keyLength:uint= key.length;
|
||||
var keyIndex:uint = 0;
|
||||
|
||||
for (var i:uint = 0; i < P_SZ; i++)
|
||||
{
|
||||
// get the 32 bits of the key, in 4 * 8 bit chunks
|
||||
var data:uint = 0x0000000;
|
||||
for (var j:uint = 0; j < 4; j++)
|
||||
{
|
||||
// create a 32 bit block
|
||||
data = (data << 8) | (key[keyIndex++] & 0xff);
|
||||
|
||||
// wrap when we get to the end of the key
|
||||
if (keyIndex >= keyLength)
|
||||
{
|
||||
keyIndex = 0;
|
||||
}
|
||||
}
|
||||
// XOR the newly created 32 bit chunk onto the P-array
|
||||
P[i] ^= data;
|
||||
}
|
||||
|
||||
/*
|
||||
* (3) Encrypt the all-zero string with the Blowfish algorithm, using
|
||||
* the subkeys described in (1) and (2)
|
||||
*
|
||||
* (4) Replace P1 and P2 with the output of step (3)
|
||||
*
|
||||
* (5) Encrypt the output of step(3) using the Blowfish algorithm, with
|
||||
* the modified subkeys.
|
||||
*
|
||||
* (6) Replace P3 and P4 with the output of step (5)
|
||||
*
|
||||
* (7) Continue the process, replacing all elements of the P-array and
|
||||
* then all four S-boxes in order, with the output of the continuously
|
||||
* changing Blowfish algorithm
|
||||
*/
|
||||
|
||||
processTable(0, 0, P);
|
||||
processTable(P[P_SZ - 2], P[P_SZ - 1], S0);
|
||||
processTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);
|
||||
processTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);
|
||||
processTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the given input starting at the given offset and place the result
|
||||
* in the provided buffer starting at the given offset. The input will be an
|
||||
* exact multiple of our blocksize.
|
||||
*/
|
||||
private function encryptBlock(src:ByteArray, srcIndex:uint, dst:ByteArray, dstIndex:uint):void
|
||||
{
|
||||
var xl:uint = BytesTo32bits(src, srcIndex);
|
||||
var xr:uint = BytesTo32bits(src, srcIndex + 4);
|
||||
|
||||
xl ^= P[0];
|
||||
|
||||
for (var i:uint = 1; i < ROUNDS; i += 2)
|
||||
{
|
||||
xr ^= F(xl) ^ P[i];
|
||||
xl ^= F(xr) ^ P[i + 1];
|
||||
}
|
||||
|
||||
xr ^= P[ROUNDS + 1];
|
||||
|
||||
Bits32ToBytes(xr, dst, dstIndex);
|
||||
Bits32ToBytes(xl, dst, dstIndex + 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the given input starting at the given offset and place the result
|
||||
* in the provided buffer starting at the given offset. The input will be an
|
||||
* exact multiple of our blocksize.
|
||||
*/
|
||||
private function decryptBlock(src:ByteArray, srcIndex:uint, dst:ByteArray, dstIndex:uint):void
|
||||
{
|
||||
var xl:uint = BytesTo32bits(src, srcIndex);
|
||||
var xr:uint = BytesTo32bits(src, srcIndex + 4);
|
||||
|
||||
xl ^= P[ROUNDS + 1];
|
||||
|
||||
for (var i:uint = ROUNDS; i > 0; i -= 2)
|
||||
{
|
||||
xr ^= F(xl) ^ P[i];
|
||||
xl ^= F(xr) ^ P[i - 1];
|
||||
}
|
||||
|
||||
xr ^= P[0];
|
||||
|
||||
Bits32ToBytes(xr, dst, dstIndex);
|
||||
Bits32ToBytes(xl, dst, dstIndex + 4);
|
||||
}
|
||||
|
||||
private function BytesTo32bits(b:ByteArray, i:uint):uint
|
||||
{
|
||||
return ((b[i] & 0xff) << 24) | ((b[i + 1] & 0xff) << 16) | ((b[i + 2] & 0xff) << 8) | ((b[i + 3] & 0xff));
|
||||
}
|
||||
|
||||
private function Bits32ToBytes(i:uint, b:ByteArray, offset:uint):void
|
||||
{
|
||||
b[offset + 3] = i;
|
||||
b[offset + 2] = (i >> 8);
|
||||
b[offset + 1] = (i >> 16);
|
||||
b[offset] = (i >> 24);
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return "blowfish";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* CBCMode
|
||||
*
|
||||
* An ActionScript 3 implementation of the CBC confidentiality mode
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
/**
|
||||
* CBC confidentiality mode. why not.
|
||||
*/
|
||||
public class CBCMode extends IVMode implements IMode
|
||||
{
|
||||
|
||||
public function CBCMode(key:ISymmetricKey, padding:IPad = null) {
|
||||
super(key, padding);
|
||||
}
|
||||
|
||||
public function encrypt(src:ByteArray):void {
|
||||
padding.pad(src);
|
||||
var vector:ByteArray = getIV4e();
|
||||
for (var i:uint=0;i<src.length;i+=blockSize) {
|
||||
for (var j:uint=0;j<blockSize;j++) {
|
||||
src[i+j] ^= vector[j];
|
||||
}
|
||||
key.encrypt(src, i);
|
||||
vector.position=0;
|
||||
vector.writeBytes(src, i, blockSize);
|
||||
}
|
||||
}
|
||||
public function decrypt(src:ByteArray):void {
|
||||
var vector:ByteArray = getIV4d();
|
||||
var tmp:ByteArray = new ByteArray;
|
||||
for (var i:uint=0;i<src.length;i+=blockSize) {
|
||||
tmp.position=0;
|
||||
tmp.writeBytes(src, i, blockSize);
|
||||
key.decrypt(src, i);
|
||||
for (var j:uint=0;j<blockSize;j++) {
|
||||
src[i+j] ^= vector[j];
|
||||
}
|
||||
vector.position=0;
|
||||
vector.writeBytes(tmp, 0, blockSize);
|
||||
}
|
||||
padding.unpad(src);
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return key.toString()+"-cbc";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* CFB8Mode
|
||||
*
|
||||
* An ActionScript 3 implementation of the CFB-8 confidentiality mode
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import com.hurlant.crypto.tests.TestCase;
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
/**
|
||||
*
|
||||
* Note: The constructor accepts an optional padding argument, but ignores it otherwise.
|
||||
*/
|
||||
public class CFB8Mode extends IVMode implements IMode
|
||||
{
|
||||
public function CFB8Mode(key:ISymmetricKey, padding:IPad = null) {
|
||||
super(key, null);
|
||||
}
|
||||
|
||||
public function encrypt(src:ByteArray):void {
|
||||
var vector:ByteArray = getIV4e();
|
||||
var tmp:ByteArray = new ByteArray;
|
||||
for (var i:uint=0;i<src.length;i++) {
|
||||
tmp.position = 0;
|
||||
tmp.writeBytes(vector);
|
||||
key.encrypt(vector);
|
||||
src[i] ^= vector[0];
|
||||
// rotate
|
||||
for (var j:uint=0;j<blockSize-1;j++) {
|
||||
vector[j] = tmp[j+1];
|
||||
}
|
||||
vector[blockSize-1] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
public function decrypt(src:ByteArray):void {
|
||||
var vector:ByteArray = getIV4d();
|
||||
var tmp:ByteArray = new ByteArray;
|
||||
for (var i:uint=0;i<src.length;i++) {
|
||||
var c:uint = src[i];
|
||||
tmp.position = 0;
|
||||
tmp.writeBytes(vector); // I <- tmp
|
||||
key.encrypt(vector); // O <- vector
|
||||
src[i] ^= vector[0];
|
||||
// rotate
|
||||
for (var j:uint=0;j<blockSize-1;j++) {
|
||||
vector[j] = tmp[j+1];
|
||||
}
|
||||
vector[blockSize-1] = c;
|
||||
}
|
||||
|
||||
}
|
||||
public function toString():String {
|
||||
return key.toString()+"-cfb8";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* CFBMode
|
||||
*
|
||||
* An ActionScript 3 implementation of the CFB confidentiality mode
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
/**
|
||||
* This is the "full" CFB.
|
||||
* CFB1 and CFB8 are hiding somewhere else.
|
||||
*
|
||||
* Note: The constructor accepts an optional padding argument, but ignores it otherwise.
|
||||
*/
|
||||
public class CFBMode extends IVMode implements IMode
|
||||
{
|
||||
|
||||
public function CFBMode(key:ISymmetricKey, padding:IPad = null) {
|
||||
super(key,null);
|
||||
}
|
||||
|
||||
public function encrypt(src:ByteArray):void
|
||||
{
|
||||
var l:uint = src.length;
|
||||
var vector:ByteArray = getIV4e();
|
||||
for (var i:uint=0;i<src.length;i+=blockSize) {
|
||||
key.encrypt(vector);
|
||||
var chunk:uint = (i+blockSize<l)?blockSize:l-i;
|
||||
for (var j:uint=0;j<chunk;j++) {
|
||||
src[i+j] ^= vector[j];
|
||||
}
|
||||
vector.position=0;
|
||||
vector.writeBytes(src, i, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
public function decrypt(src:ByteArray):void
|
||||
{
|
||||
var l:uint = src.length;
|
||||
var vector:ByteArray = getIV4d();
|
||||
var tmp:ByteArray = new ByteArray;
|
||||
for (var i:uint=0;i<src.length;i+=blockSize) {
|
||||
key.encrypt(vector);
|
||||
var chunk:uint = (i+blockSize<l)?blockSize:l-i;
|
||||
tmp.position=0;
|
||||
tmp.writeBytes(src, i, chunk);
|
||||
for (var j:uint=0;j<chunk;j++) {
|
||||
src[i+j] ^= vector[j];
|
||||
}
|
||||
vector.position=0;
|
||||
vector.writeBytes(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return key.toString()+"-cfb";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* CTRMode
|
||||
*
|
||||
* An ActionScript 3 implementation of the counter confidentiality mode
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public class CTRMode extends IVMode implements IMode
|
||||
{
|
||||
|
||||
public function CTRMode(key:ISymmetricKey, padding:IPad = null) {
|
||||
super(key, padding);
|
||||
}
|
||||
|
||||
public function encrypt(src:ByteArray):void
|
||||
{
|
||||
padding.pad(src);
|
||||
var vector:ByteArray = getIV4e();
|
||||
core(src, vector);
|
||||
}
|
||||
|
||||
public function decrypt(src:ByteArray):void
|
||||
{
|
||||
var vector:ByteArray = getIV4d();
|
||||
core(src, vector);
|
||||
padding.unpad(src);
|
||||
}
|
||||
|
||||
private function core(src:ByteArray, iv:ByteArray):void {
|
||||
var X:ByteArray = new ByteArray;
|
||||
var Xenc:ByteArray = new ByteArray;
|
||||
X.writeBytes(iv);
|
||||
for (var i:uint=0;i<src.length;i+=blockSize) {
|
||||
Xenc.position=0;
|
||||
Xenc.writeBytes(X);
|
||||
key.encrypt(Xenc);
|
||||
for (var j:uint=0;j<blockSize;j++) {
|
||||
src[i+j] ^= Xenc[j];
|
||||
}
|
||||
|
||||
for (j=blockSize-1;j>=0;--j) {
|
||||
X[j]++;
|
||||
if (X[j]!=0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
public function toString():String {
|
||||
return key.toString()+"-ctr";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
/**
|
||||
* DESKey
|
||||
*
|
||||
* An Actionscript 3 implementation of the Data Encryption Standard (DES)
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from:
|
||||
* The Bouncy Castle Crypto package,
|
||||
* Copyright (c) 2000-2004 The Legion Of The Bouncy Castle
|
||||
* (http://www.bouncycastle.org)
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Hex;
|
||||
import com.hurlant.util.Memory;
|
||||
|
||||
public class DESKey implements ISymmetricKey
|
||||
{
|
||||
/**
|
||||
* what follows is mainly taken from "Applied Cryptography", by Bruce
|
||||
* Schneier, however it also bears great resemblance to Richard
|
||||
* Outerbridge's D3DES...
|
||||
*/
|
||||
|
||||
private static const Df_Key:Array = [ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
|
||||
0x10, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67 ];
|
||||
|
||||
private static const bytebit:Array = [ 128, 64, 32, 16, 8, 4, 2, 1 ];
|
||||
|
||||
private static const bigbyte:Array = [ 0x800000, 0x400000, 0x200000, 0x100000, 0x80000, 0x40000, 0x20000, 0x10000, 0x8000,
|
||||
0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 ];
|
||||
|
||||
/*
|
||||
* Use the key schedule specified in the Standard (ANSI X3.92-1981).
|
||||
*/
|
||||
|
||||
private static const pc1:Array = [ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2,
|
||||
59, 51, 43, 35, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, 28, 20, 12,
|
||||
4, 27, 19, 11, 3 ];
|
||||
|
||||
private static const totrot:Array = [ 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 ];
|
||||
|
||||
private static const pc2:Array = [ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 40,
|
||||
51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 ];
|
||||
|
||||
private static const SP1:Array = [ 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004,
|
||||
0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004,
|
||||
0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004,
|
||||
0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404,
|
||||
0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400,
|
||||
0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404,
|
||||
0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004,
|
||||
0x00010400, 0x00000000, 0x01010004 ];
|
||||
|
||||
private static const SP2:Array = [ 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020,
|
||||
0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020,
|
||||
0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020,
|
||||
0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020,
|
||||
0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020,
|
||||
0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020,
|
||||
0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000,
|
||||
0x80100020, 0x80108020, 0x00108000 ];
|
||||
|
||||
private static const SP3:Array = [ 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208,
|
||||
0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208,
|
||||
0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208,
|
||||
0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000,
|
||||
0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208,
|
||||
0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208,
|
||||
0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208,
|
||||
0x00000008, 0x08020008, 0x00020200 ];
|
||||
|
||||
private static const SP4:Array = [ 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001,
|
||||
0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001,
|
||||
0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081,
|
||||
0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001,
|
||||
0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081,
|
||||
0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000,
|
||||
0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080,
|
||||
0x00800000, 0x00002000, 0x00802080 ];
|
||||
|
||||
private static const SP5:Array = [ 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000,
|
||||
0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000,
|
||||
0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000,
|
||||
0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100,
|
||||
0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000,
|
||||
0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100,
|
||||
0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000,
|
||||
0x40080000, 0x02080100, 0x40000100 ];
|
||||
|
||||
private static const SP6:Array = [ 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010,
|
||||
0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010,
|
||||
0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010,
|
||||
0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010,
|
||||
0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000,
|
||||
0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010,
|
||||
0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000,
|
||||
0x20000000, 0x00400010, 0x20004010 ];
|
||||
|
||||
private static const SP7:Array = [ 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802,
|
||||
0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802,
|
||||
0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000,
|
||||
0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800,
|
||||
0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800,
|
||||
0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000,
|
||||
0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002,
|
||||
0x04000800, 0x00000800, 0x00200002 ];
|
||||
|
||||
private static const SP8:Array = [ 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040,
|
||||
0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040,
|
||||
0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040,
|
||||
0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000,
|
||||
0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040,
|
||||
0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040,
|
||||
0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040,
|
||||
0x00040040, 0x10000000, 0x10041000 ];
|
||||
|
||||
|
||||
protected var key:ByteArray;
|
||||
protected var encKey:Array;
|
||||
protected var decKey:Array;
|
||||
|
||||
|
||||
public function DESKey(key:ByteArray) {
|
||||
this.key = key;
|
||||
this.encKey = generateWorkingKey(true, key, 0);
|
||||
this.decKey = generateWorkingKey(false, key, 0);
|
||||
}
|
||||
|
||||
public function getBlockSize():uint
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
public function decrypt(block:ByteArray, index:uint=0):void
|
||||
{
|
||||
desFunc(decKey, block, index, block, index);
|
||||
}
|
||||
|
||||
public function dispose():void
|
||||
{
|
||||
var i:uint=0;
|
||||
for (i=0;i<encKey.length;i++) { encKey[i]=0; }
|
||||
for (i=0;i<decKey.length;i++) { decKey[i]=0; }
|
||||
encKey=null;
|
||||
decKey=null;
|
||||
for (i=0;i<key.length;i++) { key[i]=0; }
|
||||
key.length = 0;
|
||||
key = null;
|
||||
Memory.gc();
|
||||
}
|
||||
|
||||
public function encrypt(block:ByteArray, index:uint=0):void
|
||||
{
|
||||
desFunc(encKey, block, index, block, index);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* generate an integer based working key based on our secret key and what we
|
||||
* processing we are planning to do.
|
||||
*
|
||||
* Acknowledgements for this routine go to James Gillogly & Phil Karn.
|
||||
*/
|
||||
protected function generateWorkingKey(encrypting:Boolean, key:ByteArray, off:uint):Array
|
||||
{
|
||||
//int[] newKey = new int[32];
|
||||
var newKey:Array = [];
|
||||
//boolean[] pc1m = new boolean[56], pcr = new boolean[56];
|
||||
var pc1m:ByteArray = new ByteArray;
|
||||
var pcr:ByteArray = new ByteArray;
|
||||
|
||||
var l:uint;
|
||||
|
||||
for (var j:uint = 0; j < 56; j++)
|
||||
{
|
||||
l = pc1[j];
|
||||
|
||||
pc1m[j] = ((key[off + (l >>> 3)] & bytebit[l & 07]) != 0);
|
||||
}
|
||||
|
||||
for (var i:uint = 0; i < 16; i++)
|
||||
{
|
||||
var m:uint;
|
||||
var n:uint;
|
||||
|
||||
if (encrypting)
|
||||
{
|
||||
m = i << 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = (15 - i) << 1;
|
||||
}
|
||||
|
||||
n = m + 1;
|
||||
newKey[m] = newKey[n] = 0;
|
||||
|
||||
for (j = 0; j < 28; j++)
|
||||
{
|
||||
l = j + totrot[i];
|
||||
if (l < 28)
|
||||
{
|
||||
pcr[j] = pc1m[l];
|
||||
}
|
||||
else
|
||||
{
|
||||
pcr[j] = pc1m[l - 28];
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 28; j < 56; j++)
|
||||
{
|
||||
l = j + totrot[i];
|
||||
if (l < 56)
|
||||
{
|
||||
pcr[j] = pc1m[l];
|
||||
}
|
||||
else
|
||||
{
|
||||
pcr[j] = pc1m[l - 28];
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < 24; j++)
|
||||
{
|
||||
if (pcr[pc2[j]])
|
||||
{
|
||||
newKey[m] |= bigbyte[j];
|
||||
}
|
||||
|
||||
if (pcr[pc2[j + 24]])
|
||||
{
|
||||
newKey[n] |= bigbyte[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// store the processed key
|
||||
//
|
||||
for (i = 0; i != 32; i += 2)
|
||||
{
|
||||
var i1:uint;
|
||||
var i2:uint;
|
||||
|
||||
i1 = newKey[i];
|
||||
i2 = newKey[i + 1];
|
||||
|
||||
newKey[i] = ((i1 & 0x00fc0000) << 6) | ((i1 & 0x00000fc0) << 10) | ((i2 & 0x00fc0000) >>> 10)
|
||||
| ((i2 & 0x00000fc0) >>> 6);
|
||||
|
||||
newKey[i + 1] = ((i1 & 0x0003f000) << 12) | ((i1 & 0x0000003f) << 16) | ((i2 & 0x0003f000) >>> 4)
|
||||
| (i2 & 0x0000003f);
|
||||
}
|
||||
return newKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* the DES engine.
|
||||
*/
|
||||
protected function desFunc(wKey:Array, inp:ByteArray, inOff:uint, out:ByteArray, outOff:uint):void
|
||||
{
|
||||
var work:uint;
|
||||
var right:uint;
|
||||
var left:uint;
|
||||
|
||||
left = (inp[inOff + 0] & 0xff) << 24;
|
||||
left |= (inp[inOff + 1] & 0xff) << 16;
|
||||
left |= (inp[inOff + 2] & 0xff) << 8;
|
||||
left |= (inp[inOff + 3] & 0xff);
|
||||
|
||||
right = (inp[inOff + 4] & 0xff) << 24;
|
||||
right |= (inp[inOff + 5] & 0xff) << 16;
|
||||
right |= (inp[inOff + 6] & 0xff) << 8;
|
||||
right |= (inp[inOff + 7] & 0xff);
|
||||
|
||||
work = ((left >>> 4) ^ right) & 0x0f0f0f0f;
|
||||
right ^= work;
|
||||
left ^= (work << 4);
|
||||
work = ((left >>> 16) ^ right) & 0x0000ffff;
|
||||
right ^= work;
|
||||
left ^= (work << 16);
|
||||
work = ((right >>> 2) ^ left) & 0x33333333;
|
||||
left ^= work;
|
||||
right ^= (work << 2);
|
||||
work = ((right >>> 8) ^ left) & 0x00ff00ff;
|
||||
left ^= work;
|
||||
right ^= (work << 8);
|
||||
right = ((right << 1) | ((right >>> 31) & 1)) & 0xffffffff;
|
||||
work = (left ^ right) & 0xaaaaaaaa;
|
||||
left ^= work;
|
||||
right ^= work;
|
||||
left = ((left << 1) | ((left >>> 31) & 1)) & 0xffffffff;
|
||||
|
||||
for (var round:uint = 0; round < 8; round++)
|
||||
{
|
||||
var fval:uint;
|
||||
|
||||
work = (right << 28) | (right >>> 4);
|
||||
work ^= wKey[round * 4 + 0];
|
||||
fval = SP7[work & 0x3f];
|
||||
fval |= SP5[(work >>> 8) & 0x3f];
|
||||
fval |= SP3[(work >>> 16) & 0x3f];
|
||||
fval |= SP1[(work >>> 24) & 0x3f];
|
||||
work = right ^ wKey[round * 4 + 1];
|
||||
fval |= SP8[work & 0x3f];
|
||||
fval |= SP6[(work >>> 8) & 0x3f];
|
||||
fval |= SP4[(work >>> 16) & 0x3f];
|
||||
fval |= SP2[(work >>> 24) & 0x3f];
|
||||
left ^= fval;
|
||||
work = (left << 28) | (left >>> 4);
|
||||
work ^= wKey[round * 4 + 2];
|
||||
fval = SP7[work & 0x3f];
|
||||
fval |= SP5[(work >>> 8) & 0x3f];
|
||||
fval |= SP3[(work >>> 16) & 0x3f];
|
||||
fval |= SP1[(work >>> 24) & 0x3f];
|
||||
work = left ^ wKey[round * 4 + 3];
|
||||
fval |= SP8[work & 0x3f];
|
||||
fval |= SP6[(work >>> 8) & 0x3f];
|
||||
fval |= SP4[(work >>> 16) & 0x3f];
|
||||
fval |= SP2[(work >>> 24) & 0x3f];
|
||||
right ^= fval;
|
||||
}
|
||||
|
||||
right = (right << 31) | (right >>> 1);
|
||||
work = (left ^ right) & 0xaaaaaaaa;
|
||||
left ^= work;
|
||||
right ^= work;
|
||||
left = (left << 31) | (left >>> 1);
|
||||
work = ((left >>> 8) ^ right) & 0x00ff00ff;
|
||||
right ^= work;
|
||||
left ^= (work << 8);
|
||||
work = ((left >>> 2) ^ right) & 0x33333333;
|
||||
right ^= work;
|
||||
left ^= (work << 2);
|
||||
work = ((right >>> 16) ^ left) & 0x0000ffff;
|
||||
left ^= work;
|
||||
right ^= (work << 16);
|
||||
work = ((right >>> 4) ^ left) & 0x0f0f0f0f;
|
||||
left ^= work;
|
||||
right ^= (work << 4);
|
||||
|
||||
out[outOff + 0] = ((right >>> 24) & 0xff);
|
||||
out[outOff + 1] = ((right >>> 16) & 0xff);
|
||||
out[outOff + 2] = ((right >>> 8) & 0xff);
|
||||
out[outOff + 3] = (right & 0xff);
|
||||
out[outOff + 4] = ((left >>> 24) & 0xff);
|
||||
out[outOff + 5] = ((left >>> 16) & 0xff);
|
||||
out[outOff + 6] = ((left >>> 8) & 0xff);
|
||||
out[outOff + 7] = (left & 0xff);
|
||||
}
|
||||
|
||||
|
||||
public function toString():String {
|
||||
return "des";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* ECBMode
|
||||
*
|
||||
* An ActionScript 3 implementation of the ECB confidentiality mode
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Memory;
|
||||
import com.hurlant.util.Hex;
|
||||
|
||||
/**
|
||||
* ECB mode.
|
||||
* This uses a padding and a symmetric key.
|
||||
* If no padding is given, PKCS#5 is used.
|
||||
*/
|
||||
public class ECBMode implements IMode, ICipher
|
||||
{
|
||||
private var key:ISymmetricKey;
|
||||
private var padding:IPad;
|
||||
|
||||
public function ECBMode(key:ISymmetricKey, padding:IPad = null) {
|
||||
this.key = key;
|
||||
if (padding == null) {
|
||||
padding = new PKCS5(key.getBlockSize());
|
||||
} else {
|
||||
padding.setBlockSize(key.getBlockSize());
|
||||
}
|
||||
this.padding = padding;
|
||||
}
|
||||
|
||||
public function getBlockSize():uint {
|
||||
return key.getBlockSize();
|
||||
}
|
||||
|
||||
public function encrypt(src:ByteArray):void {
|
||||
padding.pad(src);
|
||||
src.position = 0;
|
||||
var blockSize:uint = key.getBlockSize();
|
||||
var tmp:ByteArray = new ByteArray;
|
||||
var dst:ByteArray = new ByteArray;
|
||||
for (var i:uint=0;i<src.length;i+=blockSize) {
|
||||
tmp.length=0;
|
||||
src.readBytes(tmp, 0, blockSize);
|
||||
key.encrypt(tmp);
|
||||
dst.writeBytes(tmp);
|
||||
}
|
||||
src.length=0;
|
||||
src.writeBytes(dst);
|
||||
}
|
||||
public function decrypt(src:ByteArray):void {
|
||||
src.position = 0;
|
||||
var blockSize:uint = key.getBlockSize();
|
||||
|
||||
// sanity check.
|
||||
if (src.length%blockSize!=0) {
|
||||
throw new Error("ECB mode cipher length must be a multiple of blocksize "+blockSize);
|
||||
}
|
||||
|
||||
var tmp:ByteArray = new ByteArray;
|
||||
var dst:ByteArray = new ByteArray;
|
||||
for (var i:uint=0;i<src.length;i+=blockSize) {
|
||||
tmp.length=0;
|
||||
src.readBytes(tmp, 0, blockSize);
|
||||
|
||||
key.decrypt(tmp);
|
||||
dst.writeBytes(tmp);
|
||||
}
|
||||
padding.unpad(dst);
|
||||
src.length=0;
|
||||
src.writeBytes(dst);
|
||||
}
|
||||
public function dispose():void {
|
||||
key.dispose();
|
||||
key = null;
|
||||
padding = null;
|
||||
Memory.gc();
|
||||
}
|
||||
public function toString():String {
|
||||
return key.toString()+"-ecb";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* ICipher
|
||||
*
|
||||
* A generic interface to use symmetric ciphers
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public interface ICipher
|
||||
{
|
||||
function getBlockSize():uint;
|
||||
function encrypt(src:ByteArray):void;
|
||||
function decrypt(src:ByteArray):void;
|
||||
function dispose():void;
|
||||
function toString():String;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* IMode
|
||||
*
|
||||
* An interface for confidentiality modes to implement
|
||||
* This could become deprecated at some point.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
public interface IMode extends ICipher
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* IPad
|
||||
*
|
||||
* An interface for padding mechanisms to implement.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
/**
|
||||
* Tiny interface that represents a padding mechanism.
|
||||
*/
|
||||
public interface IPad
|
||||
{
|
||||
/**
|
||||
* Add padding to the array
|
||||
*/
|
||||
function pad(a:ByteArray):void;
|
||||
/**
|
||||
* Remove padding from the array.
|
||||
* @throws Error if the padding is invalid.
|
||||
*/
|
||||
function unpad(a:ByteArray):void;
|
||||
/**
|
||||
* Set the blockSize to work on
|
||||
*/
|
||||
function setBlockSize(bs:uint):void;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* IStreamCipher
|
||||
*
|
||||
* A "marker" interface for stream ciphers.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric {
|
||||
|
||||
/**
|
||||
* A marker to indicate how this cipher works.
|
||||
* A stream cipher:
|
||||
* - does not use initialization vector
|
||||
* - keeps some internal state between calls to encrypt() and decrypt()
|
||||
*
|
||||
*/
|
||||
public interface IStreamCipher extends ICipher {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* ISymmetricKey
|
||||
*
|
||||
* An interface for symmetric encryption keys to implement.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public interface ISymmetricKey
|
||||
{
|
||||
/**
|
||||
* Returns the block size used by this particular encryption algorithm
|
||||
*/
|
||||
function getBlockSize():uint;
|
||||
/**
|
||||
* Encrypt one block of data in "block", starting at "index", of length "getBlockSize()"
|
||||
*/
|
||||
function encrypt(block:ByteArray, index:uint=0):void;
|
||||
/**
|
||||
* Decrypt one block of data in "block", starting at "index", of length "getBlockSize()"
|
||||
*/
|
||||
function decrypt(block:ByteArray, index:uint=0):void;
|
||||
/**
|
||||
* Attempts to destroy sensitive information from memory, such as encryption keys.
|
||||
* Note: This is not guaranteed to work given the Flash sandbox model.
|
||||
*/
|
||||
function dispose():void;
|
||||
|
||||
function toString():String;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* IVMode
|
||||
*
|
||||
* An abstract class for confidentialy modes that rely on an initialization vector.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import com.hurlant.crypto.prng.Random;
|
||||
import com.hurlant.crypto.tests.TestCase;
|
||||
import com.hurlant.util.Memory;
|
||||
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
/**
|
||||
* An "abtract" class to avoid redundant code in subclasses
|
||||
*/
|
||||
public class IVMode
|
||||
{
|
||||
protected var key:ISymmetricKey;
|
||||
protected var padding:IPad;
|
||||
// random generator used to generate IVs
|
||||
protected var prng:Random;
|
||||
// optional static IV. used for testing only.
|
||||
protected var iv:ByteArray;
|
||||
// generated IV is stored here.
|
||||
protected var lastIV:ByteArray;
|
||||
protected var blockSize:uint;
|
||||
|
||||
|
||||
public function IVMode(key:ISymmetricKey, padding:IPad = null) {
|
||||
this.key = key;
|
||||
blockSize = key.getBlockSize();
|
||||
if (padding == null) {
|
||||
padding = new PKCS5(blockSize);
|
||||
} else {
|
||||
padding.setBlockSize(blockSize);
|
||||
}
|
||||
this.padding = padding;
|
||||
|
||||
prng = new Random;
|
||||
iv = null;
|
||||
lastIV = new ByteArray;
|
||||
}
|
||||
|
||||
public function getBlockSize():uint {
|
||||
return key.getBlockSize();
|
||||
}
|
||||
public function dispose():void {
|
||||
var i:uint;
|
||||
if (iv != null) {
|
||||
for (i=0;i<iv.length;i++) {
|
||||
iv[i] = prng.nextByte();
|
||||
}
|
||||
iv.length=0;
|
||||
iv = null;
|
||||
}
|
||||
if (lastIV != null) {
|
||||
for (i=0;i<iv.length;i++) {
|
||||
lastIV[i] = prng.nextByte();
|
||||
}
|
||||
lastIV.length=0;
|
||||
lastIV=null;
|
||||
}
|
||||
key.dispose();
|
||||
key = null;
|
||||
padding = null;
|
||||
prng.dispose();
|
||||
prng = null;
|
||||
Memory.gc();
|
||||
}
|
||||
/**
|
||||
* Optional function to force the IV value.
|
||||
* Normally, an IV gets generated randomly at every encrypt() call.
|
||||
* Also, use this to set the IV before calling decrypt()
|
||||
* (if not set before decrypt(), the IV is read from the beginning of the stream.)
|
||||
*/
|
||||
public function set IV(value:ByteArray):void {
|
||||
iv = value;
|
||||
lastIV.length=0;
|
||||
lastIV.writeBytes(iv);
|
||||
}
|
||||
public function get IV():ByteArray {
|
||||
return lastIV;
|
||||
}
|
||||
|
||||
protected function getIV4e():ByteArray {
|
||||
var vec:ByteArray = new ByteArray;
|
||||
if (iv) {
|
||||
vec.writeBytes(iv);
|
||||
} else {
|
||||
prng.nextBytes(vec, blockSize);
|
||||
}
|
||||
lastIV.length=0;
|
||||
lastIV.writeBytes(vec);
|
||||
return vec;
|
||||
}
|
||||
protected function getIV4d():ByteArray {
|
||||
var vec:ByteArray = new ByteArray;
|
||||
if (iv) {
|
||||
vec.writeBytes(iv);
|
||||
} else {
|
||||
throw new Error("an IV must be set before calling decrypt()");
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* NullPad
|
||||
*
|
||||
* A padding class that doesn't pad.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
/**
|
||||
* A pad that does nothing.
|
||||
* Useful when you don't want padding in your Mode.
|
||||
*/
|
||||
public class NullPad implements IPad
|
||||
{
|
||||
public function unpad(a:ByteArray):void
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public function pad(a:ByteArray):void
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public function setBlockSize(bs:uint):void {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* OFBMode
|
||||
*
|
||||
* An ActionScript 3 implementation of the OFB confidentiality mode
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public class OFBMode extends IVMode implements IMode
|
||||
{
|
||||
public function OFBMode(key:ISymmetricKey, padding:IPad=null)
|
||||
{
|
||||
super(key, null);
|
||||
}
|
||||
|
||||
public function encrypt(src:ByteArray):void
|
||||
{
|
||||
var vector:ByteArray = getIV4e();
|
||||
core(src, vector);
|
||||
}
|
||||
|
||||
public function decrypt(src:ByteArray):void
|
||||
{
|
||||
var vector:ByteArray = getIV4d();
|
||||
core(src, vector);
|
||||
}
|
||||
|
||||
private function core(src:ByteArray, iv:ByteArray):void {
|
||||
var l:uint = src.length;
|
||||
var tmp:ByteArray = new ByteArray;
|
||||
for (var i:uint=0;i<src.length;i+=blockSize) {
|
||||
key.encrypt(iv);
|
||||
tmp.position=0;
|
||||
tmp.writeBytes(iv);
|
||||
var chunk:uint = (i+blockSize<l)?blockSize:l-i;
|
||||
for (var j:uint=0;j<chunk;j++) {
|
||||
src[i+j] ^= iv[j];
|
||||
}
|
||||
iv.position=0;
|
||||
iv.writeBytes(tmp);
|
||||
}
|
||||
}
|
||||
public function toString():String {
|
||||
return key.toString()+"-ofb";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* PKCS5
|
||||
*
|
||||
* A padding implementation of PKCS5.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public class PKCS5 implements IPad
|
||||
{
|
||||
private var blockSize:uint;
|
||||
|
||||
public function PKCS5(blockSize:uint=0) {
|
||||
this.blockSize = blockSize;
|
||||
}
|
||||
|
||||
public function pad(a:ByteArray):void {
|
||||
var c:uint = blockSize-a.length%blockSize;
|
||||
for (var i:uint=0;i<c;i++){
|
||||
a[a.length] = c;
|
||||
}
|
||||
}
|
||||
public function unpad(a:ByteArray):void {
|
||||
var c:uint = a.length%blockSize;
|
||||
if (c!=0) throw new Error("PKCS#5::unpad: ByteArray.length isn't a multiple of the blockSize");
|
||||
c = a[a.length-1];
|
||||
for (var i:uint=c;i>0;i--) {
|
||||
var v:uint = a[a.length-1];
|
||||
a.length--;
|
||||
if (c!=v) throw new Error("PKCS#5:unpad: Invalid padding value. expected ["+c+"], found ["+v+"]");
|
||||
}
|
||||
// that is all.
|
||||
}
|
||||
|
||||
public function setBlockSize(bs:uint):void {
|
||||
blockSize = bs;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* TLSPad
|
||||
*
|
||||
* A padding implementation used by TLS
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric {
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Hex;
|
||||
import com.hurlant.crypto.tls.TLSError;
|
||||
|
||||
public class SSLPad implements IPad {
|
||||
private var blockSize:uint;
|
||||
|
||||
public function SSLPad(blockSize:uint=0) {
|
||||
this.blockSize = blockSize;
|
||||
}
|
||||
public function pad(a:ByteArray):void {
|
||||
var c:uint = blockSize - (a.length+1)%blockSize;
|
||||
for (var i:uint=0;i<=c;i++) {
|
||||
a[a.length] = c;
|
||||
}
|
||||
|
||||
}
|
||||
public function unpad(a:ByteArray):void {
|
||||
var c:uint = a.length%blockSize;
|
||||
if (c!=0) throw new TLSError("SSLPad::unpad: ByteArray.length isn't a multiple of the blockSize", TLSError.bad_record_mac);
|
||||
c = a[a.length-1];
|
||||
for (var i:uint=c;i>0;i--) {
|
||||
var v:uint = a[a.length-1];
|
||||
a.length--;
|
||||
// But LOOK! SSL 3.0 doesn't care about this, bytes are arbitrary!
|
||||
// if (c!=v) throw new TLSError("SSLPad:unpad: Invalid padding value. expected ["+c+"], found ["+v+"]", TLSError.bad_record_mac);
|
||||
}
|
||||
a.length--;
|
||||
|
||||
}
|
||||
public function setBlockSize(bs:uint):void {
|
||||
blockSize = bs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* SimpleIVMode
|
||||
*
|
||||
* A convenience class that automatically places the IV
|
||||
* at the beginning of the encrypted stream, so it doesn't have to
|
||||
* be handled explicitely.
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Memory;
|
||||
|
||||
public class SimpleIVMode implements IMode, ICipher
|
||||
{
|
||||
protected var mode:IVMode;
|
||||
protected var cipher:ICipher;
|
||||
|
||||
public function SimpleIVMode(mode:IVMode) {
|
||||
this.mode = mode;
|
||||
cipher = mode as ICipher;
|
||||
}
|
||||
|
||||
public function getBlockSize():uint {
|
||||
return mode.getBlockSize();
|
||||
}
|
||||
|
||||
public function dispose():void {
|
||||
mode.dispose();
|
||||
mode = null;
|
||||
cipher = null;
|
||||
Memory.gc();
|
||||
}
|
||||
|
||||
public function encrypt(src:ByteArray):void {
|
||||
cipher.encrypt(src);
|
||||
var tmp:ByteArray = new ByteArray;
|
||||
tmp.writeBytes(mode.IV);
|
||||
tmp.writeBytes(src);
|
||||
src.position=0;
|
||||
src.writeBytes(tmp);
|
||||
}
|
||||
|
||||
public function decrypt(src:ByteArray):void {
|
||||
var tmp:ByteArray = new ByteArray;
|
||||
tmp.writeBytes(src, 0, getBlockSize());
|
||||
mode.IV = tmp;
|
||||
tmp = new ByteArray;
|
||||
tmp.writeBytes(src, getBlockSize());
|
||||
cipher.decrypt(tmp);
|
||||
src.length=0;
|
||||
src.writeBytes(tmp);
|
||||
}
|
||||
public function toString():String {
|
||||
return "simple-"+cipher.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* TLSPad
|
||||
*
|
||||
* A padding implementation used by TLS
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric {
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Hex;
|
||||
import com.hurlant.crypto.tls.TLSError;
|
||||
|
||||
public class TLSPad implements IPad {
|
||||
private var blockSize:uint;
|
||||
|
||||
public function TLSPad(blockSize:uint=0) {
|
||||
this.blockSize = blockSize;
|
||||
}
|
||||
public function pad(a:ByteArray):void {
|
||||
var c:uint = blockSize - (a.length+1)%blockSize;
|
||||
for (var i:uint=0;i<=c;i++) {
|
||||
a[a.length] = c;
|
||||
}
|
||||
}
|
||||
public function unpad(a:ByteArray):void {
|
||||
var c:uint = a.length%blockSize;
|
||||
if (c!=0) throw new TLSError("TLSPad::unpad: ByteArray.length isn't a multiple of the blockSize", TLSError.bad_record_mac);
|
||||
c = a[a.length-1];
|
||||
for (var i:uint=c;i>0;i--) {
|
||||
var v:uint = a[a.length-1];
|
||||
a.length--;
|
||||
if (c!=v) throw new TLSError("TLSPad:unpad: Invalid padding value. expected ["+c+"], found ["+v+"]", TLSError.bad_record_mac);
|
||||
}
|
||||
a.length--;
|
||||
// mostly ripped off from PKCS5.as, but with subtle differences
|
||||
}
|
||||
public function setBlockSize(bs:uint):void {
|
||||
blockSize = bs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* TripleDESKey
|
||||
*
|
||||
* An Actionscript 3 implementation of Triple DES
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* Derived from:
|
||||
* The Bouncy Castle Crypto package,
|
||||
* Copyright (c) 2000-2004 The Legion Of The Bouncy Castle
|
||||
* (http://www.bouncycastle.org)
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.util.Memory;
|
||||
import com.hurlant.util.Hex;
|
||||
|
||||
public class TripleDESKey extends DESKey
|
||||
{
|
||||
protected var encKey2:Array;
|
||||
protected var encKey3:Array;
|
||||
protected var decKey2:Array;
|
||||
protected var decKey3:Array;
|
||||
|
||||
/**
|
||||
* This supports 2TDES and 3TDES.
|
||||
* If the key passed is 128 bits, 2TDES is used.
|
||||
* If the key has 192 bits, 3TDES is used.
|
||||
* Other key lengths give "undefined" results.
|
||||
*/
|
||||
public function TripleDESKey(key:ByteArray)
|
||||
{
|
||||
super(key);
|
||||
encKey2 = generateWorkingKey(false, key, 8);
|
||||
decKey2 = generateWorkingKey(true, key, 8);
|
||||
if (key.length>16) {
|
||||
encKey3 = generateWorkingKey(true, key, 16);
|
||||
decKey3 = generateWorkingKey(false, key, 16);
|
||||
} else {
|
||||
encKey3 = encKey;
|
||||
decKey3 = decKey;
|
||||
}
|
||||
}
|
||||
|
||||
public override function dispose():void
|
||||
{
|
||||
super.dispose();
|
||||
var i:uint = 0;
|
||||
if (encKey2!=null) {
|
||||
for (i=0;i<encKey2.length;i++) { encKey2[i]=0; }
|
||||
encKey2=null;
|
||||
}
|
||||
if (encKey3!=null) {
|
||||
for (i=0;i<encKey3.length;i++) { encKey3[i]=0; }
|
||||
encKey3=null;
|
||||
}
|
||||
if (decKey2!=null) {
|
||||
for (i=0;i<decKey2.length;i++) { decKey2[i]=0; }
|
||||
decKey2=null
|
||||
}
|
||||
if (decKey3!=null) {
|
||||
for (i=0;i<decKey3.length;i++) { decKey3[i]=0; }
|
||||
decKey3=null;
|
||||
}
|
||||
Memory.gc();
|
||||
}
|
||||
|
||||
public override function encrypt(block:ByteArray, index:uint=0):void
|
||||
{
|
||||
desFunc(encKey, block,index, block,index);
|
||||
desFunc(encKey2, block,index, block,index);
|
||||
desFunc(encKey3, block,index, block,index);
|
||||
}
|
||||
|
||||
public override function decrypt(block:ByteArray, index:uint=0):void
|
||||
{
|
||||
desFunc(decKey3, block, index, block, index);
|
||||
desFunc(decKey2, block, index, block, index);
|
||||
desFunc(decKey, block, index, block, index);
|
||||
}
|
||||
|
||||
public override function toString():String {
|
||||
return "3des";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* XTeaKey
|
||||
*
|
||||
* An ActionScript 3 implementation of the XTea algorithm
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.symmetric
|
||||
{
|
||||
import com.hurlant.crypto.prng.Random;
|
||||
import com.hurlant.util.Memory;
|
||||
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
|
||||
public class XTeaKey implements ISymmetricKey
|
||||
{
|
||||
public const NUM_ROUNDS:uint = 64;
|
||||
private var k:Array;
|
||||
|
||||
public function XTeaKey(a:ByteArray) {
|
||||
a.position=0;
|
||||
k = [a.readUnsignedInt(),a.readUnsignedInt(),a.readUnsignedInt(),a.readUnsignedInt()];
|
||||
}
|
||||
/**
|
||||
* K is an hex string with 32 digits.
|
||||
*/
|
||||
public static function parseKey(K:String):XTeaKey {
|
||||
var a:ByteArray = new ByteArray;
|
||||
a.writeUnsignedInt(parseInt(K.substr(0,8),16));
|
||||
a.writeUnsignedInt(parseInt(K.substr(8,8),16));
|
||||
a.writeUnsignedInt(parseInt(K.substr(16,8),16));
|
||||
a.writeUnsignedInt(parseInt(K.substr(24,8),16));
|
||||
a.position = 0;
|
||||
return new XTeaKey(a);
|
||||
}
|
||||
|
||||
public function getBlockSize():uint {
|
||||
return 8;
|
||||
}
|
||||
|
||||
public function encrypt(block:ByteArray, index:uint=0):void {
|
||||
block.position = index;
|
||||
var v0:uint = block.readUnsignedInt();
|
||||
var v1:uint = block.readUnsignedInt();
|
||||
var i:uint;
|
||||
var sum:uint =0;
|
||||
var delta:uint = 0x9E3779B9;
|
||||
for (i=0; i<NUM_ROUNDS; i++) {
|
||||
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
|
||||
sum += delta;
|
||||
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
|
||||
}
|
||||
block.position-=8;
|
||||
block.writeUnsignedInt(v0);
|
||||
block.writeUnsignedInt(v1);
|
||||
}
|
||||
|
||||
public function decrypt(block:ByteArray, index:uint=0):void {
|
||||
block.position = index;
|
||||
var v0:uint = block.readUnsignedInt();
|
||||
var v1:uint = block.readUnsignedInt();
|
||||
var i:uint;
|
||||
var delta:uint = 0x9E3779B9;
|
||||
var sum:uint = delta*NUM_ROUNDS;
|
||||
for (i=0; i<NUM_ROUNDS; i++) {
|
||||
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
|
||||
sum -= delta;
|
||||
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
|
||||
}
|
||||
block.position-=8;
|
||||
block.writeUnsignedInt(v0);
|
||||
block.writeUnsignedInt(v1);
|
||||
}
|
||||
|
||||
public function dispose():void {
|
||||
//private var k:Array;
|
||||
var r:Random = new Random;
|
||||
for (var i:uint=0;i<k.length;i++) {
|
||||
k[i] = r.nextByte();
|
||||
delete k[i];
|
||||
}
|
||||
k = null;
|
||||
Memory.gc();
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return "xtea";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub say {
|
||||
my $w = shift;
|
||||
print $w;
|
||||
print "\n";
|
||||
}
|
||||
|
||||
sub dump {
|
||||
my $i = shift;
|
||||
&say(sprintf("Sbox[%d] = _Sbox[%d]", $i, $i));
|
||||
&say(sprintf("InvSbox[%d] = _InvSbox[%d]", $i, $i));
|
||||
&say(sprintf("Xtime2Sbox[%d] = _Xtime2Sbox[%d]", $i, $i));
|
||||
&say(sprintf("Xtime3Sbox[%d] = _Xtime3Sbox[%d]", $i, $i));
|
||||
&say(sprintf("Xtime2[%d] = _Xtime2[%d]", $i, $i));
|
||||
&say(sprintf("Xtime9[%d] = _Xtime9[%d]", $i, $i));
|
||||
&say(sprintf("XtimeB[%d] = _XtimeB[%d]", $i, $i));
|
||||
&say(sprintf("XtimeD[%d] = _XtimeD[%d]", $i, $i));
|
||||
&say(sprintf("XtimeE[%d] = _XtimeE[%d]", $i, $i));
|
||||
}
|
||||
|
||||
for (my $i=0;$i<256;$i++) {
|
||||
&dump($i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* ARC4Test
|
||||
*
|
||||
* A test class for ARC4
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.tests
|
||||
{
|
||||
import com.hurlant.util.Hex;
|
||||
import flash.utils.ByteArray;
|
||||
import com.hurlant.crypto.prng.ARC4;
|
||||
|
||||
public class ARC4Test extends TestCase
|
||||
{
|
||||
public function ARC4Test(h:ITestHarness)
|
||||
{
|
||||
super(h, "ARC4 Test");
|
||||
runTest(testLameVectors,"ARC4 Test Vectors");
|
||||
h.endTestCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sad test vectors pilfered from
|
||||
* http://en.wikipedia.org/wiki/RC4
|
||||
*/
|
||||
public function testLameVectors():void {
|
||||
var keys:Array = [
|
||||
Hex.fromString("Key"),
|
||||
Hex.fromString("Wiki"),
|
||||
Hex.fromString("Secret")];
|
||||
var pts:Array = [
|
||||
Hex.fromString("Plaintext"),
|
||||
Hex.fromString("pedia"),
|
||||
Hex.fromString("Attack at dawn")];
|
||||
var cts:Array = [
|
||||
"BBF316E8D940AF0AD3",
|
||||
"1021BF0420",
|
||||
"45A01F645FC35B383552544B9BF5"];
|
||||
|
||||
for (var i:uint=0;i<keys.length;i++) {
|
||||
var key:ByteArray = Hex.toArray(keys[i]);
|
||||
var pt:ByteArray = Hex.toArray(pts[i]);
|
||||
var rc4:ARC4 = new ARC4(key);
|
||||
rc4.encrypt(pt);
|
||||
var out:String = Hex.fromArray(pt).toUpperCase();
|
||||
assert("comparing "+cts[i]+" to "+out, cts[i]==out);
|
||||
// now go back to plaintext
|
||||
rc4.init(key);
|
||||
rc4.decrypt(pt);
|
||||
out = Hex.fromArray(pt);
|
||||
assert("comparing "+pts[i]+" to "+out, pts[i]==out);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* BigIntegerTest
|
||||
*
|
||||
* A test class for BigInteger
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.tests
|
||||
{
|
||||
import com.hurlant.math.BigInteger;
|
||||
import com.hurlant.util.Hex;
|
||||
|
||||
public class BigIntegerTest extends TestCase
|
||||
{
|
||||
public function BigIntegerTest(h:ITestHarness)
|
||||
{
|
||||
super(h, "BigInteger Tests");
|
||||
runTest(testAdd, "BigInteger Addition");
|
||||
h.endTestCase();
|
||||
}
|
||||
|
||||
public function testAdd():void {
|
||||
var n1:BigInteger = BigInteger.nbv(25);
|
||||
var n2:BigInteger = BigInteger.nbv(1002);
|
||||
var n3:BigInteger = n1.add(n2);
|
||||
var v:int = n3.valueOf();
|
||||
assert("25+1002 = "+v, 25+1002==v);
|
||||
|
||||
var p:BigInteger = new BigInteger(Hex.toArray("e564d8b801a61f47"));
|
||||
var xp:BigInteger = new BigInteger(Hex.toArray("99246db2a3507fa"));
|
||||
|
||||
xp = xp.add(p);
|
||||
|
||||
assert("xp==eef71f932bdb2741", xp.toString(16)=="eef71f932bdb2741");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* BlowFishKeyTest
|
||||
*
|
||||
* A test class for BlowFishKey
|
||||
* Copyright (c) 2007 Henri Torgemane
|
||||
*
|
||||
* See LICENSE.txt for full license information.
|
||||
*/
|
||||
package com.hurlant.crypto.tests
|
||||
{
|
||||
import com.hurlant.crypto.symmetric.BlowFishKey;
|
||||
import com.hurlant.util.Hex;
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public class BlowFishKeyTest extends TestCase
|
||||
{
|
||||
public function BlowFishKeyTest(h:ITestHarness)
|
||||
{
|
||||
super(h, "BlowFishKey Test");
|
||||
runTest(testECB,"BlowFish ECB Test Vectors");
|
||||
h.endTestCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test vectors from http://www.schneier.com/code/vectors.txt
|
||||
*/
|
||||
public function testECB():void {
|
||||
var keys:Array = [
|
||||
"0000000000000000",
|
||||
"FFFFFFFFFFFFFFFF",
|
||||
"3000000000000000",
|
||||
"1111111111111111",
|
||||
"0123456789ABCDEF",
|
||||
"1111111111111111",
|
||||
"0000000000000000",
|
||||
"FEDCBA9876543210",
|
||||
"7CA110454A1A6E57",
|
||||
"0131D9619DC1376E",
|
||||
"07A1133E4A0B2686",
|
||||
"3849674C2602319E",
|
||||
"04B915BA43FEB5B6",
|
||||
"0113B970FD34F2CE",
|
||||
"0170F175468FB5E6",
|
||||
"43297FAD38E373FE",
|
||||
"07A7137045DA2A16",
|
||||
"04689104C2FD3B2F",
|
||||
"37D06BB516CB7546",
|
||||
"1F08260D1AC2465E",
|
||||
"584023641ABA6176",
|
||||
"025816164629B007",
|
||||
"49793EBC79B3258F",
|
||||
"4FB05E1515AB73A7",
|
||||
"49E95D6D4CA229BF",
|
||||
"018310DC409B26D6",
|
||||
"1C587F1C13924FEF",
|
||||
"0101010101010101",
|
||||
"1F1F1F1F0E0E0E0E",
|
||||
"E0FEE0FEF1FEF1FE",
|
||||
"0000000000000000",
|
||||
"FFFFFFFFFFFFFFFF",
|
||||
"0123456789ABCDEF",
|
||||
"FEDCBA9876543210" ];
|
||||
var pts:Array = [
|
||||
"0000000000000000",
|
||||
"FFFFFFFFFFFFFFFF",
|
||||
"1000000000000001",
|
||||
"1111111111111111",
|
||||
"1111111111111111",
|
||||
"0123456789ABCDEF",
|
||||
"0000000000000000",
|
||||
"0123456789ABCDEF",
|
||||
"01A1D6D039776742",
|
||||
"5CD54CA83DEF57DA",
|
||||
"0248D43806F67172",
|
||||
"51454B582DDF440A",
|
||||
"42FD443059577FA2",
|
||||
"059B5E0851CF143A",
|
||||
"0756D8E0774761D2",
|
||||
"762514B829BF486A",
|
||||
"3BDD119049372802",
|
||||
"26955F6835AF609A",
|
||||
"164D5E404F275232",
|
||||
"6B056E18759F5CCA",
|
||||
"004BD6EF09176062",
|
||||
"480D39006EE762F2",
|
||||
"437540C8698F3CFA",
|
||||
"072D43A077075292",
|
||||
"02FE55778117F12A",
|
||||
"1D9D5C5018F728C2",
|
||||
"305532286D6F295A",
|
||||
"0123456789ABCDEF",
|
||||
"0123456789ABCDEF",
|
||||
"0123456789ABCDEF",
|
||||
"FFFFFFFFFFFFFFFF",
|
||||
"0000000000000000",
|
||||
"0000000000000000",
|
||||
"FFFFFFFFFFFFFFFF" ];
|
||||
var cts:Array = [
|
||||
"4EF997456198DD78",
|
||||
"51866FD5B85ECB8A",
|
||||
"7D856F9A613063F2",
|
||||
"2466DD878B963C9D",
|
||||
"61F9C3802281B096",
|
||||
"7D0CC630AFDA1EC7",
|
||||
"4EF997456198DD78",
|
||||
"0ACEAB0FC6A0A28D",
|
||||
"59C68245EB05282B",
|
||||
"B1B8CC0B250F09A0",
|
||||
"1730E5778BEA1DA4",
|
||||
"A25E7856CF2651EB",
|
||||
"353882B109CE8F1A",
|
||||
"48F4D0884C379918",
|
||||
"432193B78951FC98",
|
||||
"13F04154D69D1AE5",
|
||||
"2EEDDA93FFD39C79",
|
||||
"D887E0393C2DA6E3",
|
||||
"5F99D04F5B163969",
|
||||
"4A057A3B24D3977B",
|
||||
"452031C1E4FADA8E",
|
||||
"7555AE39F59B87BD",
|
||||
"53C55F9CB49FC019",
|
||||
"7A8E7BFA937E89A3",
|
||||
"CF9C5D7A4986ADB5",
|
||||
"D1ABB290658BC778",
|
||||
"55CB3774D13EF201",
|
||||
"FA34EC4847B268B2",
|
||||
"A790795108EA3CAE",
|
||||
"C39E072D9FAC631D",
|
||||
"014933E0CDAFF6E4",
|
||||
"F21E9A77B71C49BC",
|
||||
"245946885754369A",
|
||||
"6B5C5A9C5D9E0A5A" ];
|
||||
|
||||
for (var i:uint=0;i<keys.length;i++) {
|
||||
var key:ByteArray = Hex.toArray(keys[i]);
|
||||
var pt:ByteArray = Hex.toArray(pts[i]);
|
||||
var bf:BlowFishKey = new BlowFishKey(key);
|
||||
bf.encrypt(pt);
|
||||
var out:String = Hex.fromArray(pt).toUpperCase();
|
||||
assert("comparing "+cts[i]+" to "+out, cts[i]==out);
|
||||
// now go back to plaintext
|
||||
bf.decrypt(pt);
|
||||
out = Hex.fromArray(pt).toUpperCase();
|
||||
assert("comparing "+pts[i]+" to "+out, pts[i]==out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user